mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-02 09:16:41 +09:00
dm io: fix discard support
commit0c535e0d6fupstream. 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 commit5fc2ffeabb(dm raid1: support discard). Signed-off-by: Milan Broz <mbroz@redhat.com> Acked-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
68294b023f
commit
a7a61e534f
@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
|
||||
unsigned offset;
|
||||
unsigned num_bvecs;
|
||||
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
|
||||
@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
|
||||
/*
|
||||
* Allocate a suitably sized-bio.
|
||||
*/
|
||||
num_bvecs = dm_sector_div_up(remaining,
|
||||
(PAGE_SIZE >> SECTOR_SHIFT));
|
||||
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs);
|
||||
if (rw & REQ_DISCARD)
|
||||
num_bvecs = 1;
|
||||
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->bi_sector = where->sector + (where->count - remaining);
|
||||
bio->bi_bdev = where->bdev;
|
||||
@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
|
||||
bio->bi_destructor = dm_bio_destructor;
|
||||
store_io_and_region_in_bio(bio, io, region);
|
||||
|
||||
/*
|
||||
* Try and add as many pages as possible.
|
||||
*/
|
||||
while (remaining) {
|
||||
if (rw & REQ_DISCARD) {
|
||||
discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
|
||||
bio->bi_size = discard_sectors << SECTOR_SHIFT;
|
||||
remaining -= discard_sectors;
|
||||
} else while (remaining) {
|
||||
/*
|
||||
* Try and add as many pages as possible.
|
||||
*/
|
||||
dp->get_page(dp, &page, &len, &offset);
|
||||
len = min(len, to_bytes(remaining));
|
||||
if (!bio_add_page(bio, page, len, offset))
|
||||
|
||||
Reference in New Issue
Block a user