Commit 0c535e0d authored by Milan Broz's avatar Milan Broz Committed by Alasdair G Kergon

dm io: fix discard support

This patch fixes a crash by recognising discards in dm_io.

Currently dm_mirror can send REQ_DISCARD bios if running over a
discard-enabled device and without support in dm_io the system
crashes badly.

BUG: unable to handle kernel paging request at 00800000
IP:  __bio_add_page.part.17+0xf5/0x1e0
...
 bio_add_page+0x56/0x70
 dispatch_io+0x1cf/0x240 [dm_mod]
 ? km_get_page+0x50/0x50 [dm_mod]
 ? vm_next_page+0x20/0x20 [dm_mod]
 ? mirror_flush+0x130/0x130 [dm_mirror]
 dm_io+0xdc/0x2b0 [dm_mod]
...

Introduced in 2.6.38-rc1 by commit 5fc2ffea
(dm raid1: support discard).
Signed-off-by: default avatarMilan Broz <mbroz@redhat.com>
Cc: stable@kernel.org
Acked-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 902c6a96
...@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
unsigned offset; unsigned offset;
unsigned num_bvecs; unsigned num_bvecs;
sector_t remaining = where->count; sector_t remaining = where->count;
struct request_queue *q = bdev_get_queue(where->bdev);
sector_t discard_sectors;
/* /*
* where->count may be zero if rw holds a flush and we need to * where->count may be zero if rw holds a flush and we need to
...@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
/* /*
* Allocate a suitably sized-bio. * Allocate a suitably sized-bio.
*/ */
num_bvecs = dm_sector_div_up(remaining, if (rw & REQ_DISCARD)
(PAGE_SIZE >> SECTOR_SHIFT)); num_bvecs = 1;
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs); else
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT)));
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining); bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev; bio->bi_bdev = where->bdev;
...@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
bio->bi_destructor = dm_bio_destructor; bio->bi_destructor = dm_bio_destructor;
store_io_and_region_in_bio(bio, io, region); store_io_and_region_in_bio(bio, io, region);
/* if (rw & REQ_DISCARD) {
* Try and add as many pages as possible. discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
*/ bio->bi_size = discard_sectors << SECTOR_SHIFT;
while (remaining) { remaining -= discard_sectors;
} else while (remaining) {
/*
* Try and add as many pages as possible.
*/
dp->get_page(dp, &page, &len, &offset); dp->get_page(dp, &page, &len, &offset);
len = min(len, to_bytes(remaining)); len = min(len, to_bytes(remaining));
if (!bio_add_page(bio, page, len, offset)) if (!bio_add_page(bio, page, len, offset))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment