Commit 0c535e0d6f463365c29623350dbd91642363c39b
Committed by
Alasdair G Kergon
1 parent
902c6a96a7
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 5fc2ffeabb9ee0fc0e71ff16b49f34f0ed3d05b4 (dm raid1: support discard). Signed-off-by: Milan Broz <mbroz@redhat.com> Cc: stable@kernel.org Acked-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Showing 1 changed file with 16 additions and 7 deletions Side-by-side Diff
drivers/md/dm-io.c
... | ... | @@ -296,6 +296,8 @@ |
296 | 296 | unsigned offset; |
297 | 297 | unsigned num_bvecs; |
298 | 298 | sector_t remaining = where->count; |
299 | + struct request_queue *q = bdev_get_queue(where->bdev); | |
300 | + sector_t discard_sectors; | |
299 | 301 | |
300 | 302 | /* |
301 | 303 | * where->count may be zero if rw holds a flush and we need to |
... | ... | @@ -305,9 +307,12 @@ |
305 | 307 | /* |
306 | 308 | * Allocate a suitably sized-bio. |
307 | 309 | */ |
308 | - num_bvecs = dm_sector_div_up(remaining, | |
309 | - (PAGE_SIZE >> SECTOR_SHIFT)); | |
310 | - num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs); | |
310 | + if (rw & REQ_DISCARD) | |
311 | + num_bvecs = 1; | |
312 | + else | |
313 | + num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), | |
314 | + dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT))); | |
315 | + | |
311 | 316 | bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); |
312 | 317 | bio->bi_sector = where->sector + (where->count - remaining); |
313 | 318 | bio->bi_bdev = where->bdev; |
... | ... | @@ -315,10 +320,14 @@ |
315 | 320 | bio->bi_destructor = dm_bio_destructor; |
316 | 321 | store_io_and_region_in_bio(bio, io, region); |
317 | 322 | |
318 | - /* | |
319 | - * Try and add as many pages as possible. | |
320 | - */ | |
321 | - while (remaining) { | |
323 | + if (rw & REQ_DISCARD) { | |
324 | + discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining); | |
325 | + bio->bi_size = discard_sectors << SECTOR_SHIFT; | |
326 | + remaining -= discard_sectors; | |
327 | + } else while (remaining) { | |
328 | + /* | |
329 | + * Try and add as many pages as possible. | |
330 | + */ | |
322 | 331 | dp->get_page(dp, &page, &len, &offset); |
323 | 332 | len = min(len, to_bytes(remaining)); |
324 | 333 | if (!bio_add_page(bio, page, len, offset)) |