Commit 0c535e0d6f463365c29623350dbd91642363c39b

Authored by Milan Broz
Committed by Alasdair G Kergon
1 parent 902c6a96a7

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

... ... @@ -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))