Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: re-add discard_granularity and alignment checks

In commit b49a087("block: remove split code in
blkdev_issue_{discard,write_same}"), discard_granularity and alignment
checks were removed. Ideally, with bio late splitting, the upper layers
shouldn't need to depend on device's limits.

Christoph reported a discard regression on the HGST Ultrastar SN100 NVMe
device when mkfs.xfs. We have not found the root cause yet.

This patch re-adds discard_granularity and alignment checks by reverting
the related changes in commit b49a087. The good thing is now we can
remove the 2G discard size cap and just use UINT_MAX to avoid bi_size
overflow.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ming Lin <ming.l@ssi.samsung.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Ming Lin and committed by
Jens Axboe
a22c4d7e 23d88271

+22 -9
+22 -9
block/blk-lib.c
··· 26 26 bio_put(bio); 27 27 } 28 28 29 - /* 30 - * Ensure that max discard sectors doesn't overflow bi_size and hopefully 31 - * it is of the proper granularity as long as the granularity is a power 32 - * of two. 33 - */ 34 - #define MAX_BIO_SECTORS ((1U << 31) >> 9) 35 - 36 29 /** 37 30 * blkdev_issue_discard - queue a discard 38 31 * @bdev: blockdev to issue discard for ··· 43 50 DECLARE_COMPLETION_ONSTACK(wait); 44 51 struct request_queue *q = bdev_get_queue(bdev); 45 52 int type = REQ_WRITE | REQ_DISCARD; 53 + unsigned int granularity; 54 + int alignment; 46 55 struct bio_batch bb; 47 56 struct bio *bio; 48 57 int ret = 0; ··· 55 60 56 61 if (!blk_queue_discard(q)) 57 62 return -EOPNOTSUPP; 63 + 64 + /* Zero-sector (unknown) and one-sector granularities are the same. */ 65 + granularity = max(q->limits.discard_granularity >> 9, 1U); 66 + alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; 58 67 59 68 if (flags & BLKDEV_DISCARD_SECURE) { 60 69 if (!blk_queue_secdiscard(q)) ··· 73 74 blk_start_plug(&plug); 74 75 while (nr_sects) { 75 76 unsigned int req_sects; 76 - sector_t end_sect; 77 + sector_t end_sect, tmp; 77 78 78 79 bio = bio_alloc(gfp_mask, 1); 79 80 if (!bio) { ··· 81 82 break; 82 83 } 83 84 84 - req_sects = min_t(sector_t, nr_sects, MAX_BIO_SECTORS); 85 + /* Make sure bi_size doesn't overflow */ 86 + req_sects = min_t(sector_t, nr_sects, UINT_MAX >> 9); 87 + 88 + /* 89 + * If splitting a request, and the next starting sector would be 90 + * misaligned, stop the discard at the previous aligned sector. 91 + */ 85 92 end_sect = sector + req_sects; 93 + tmp = end_sect; 94 + if (req_sects < nr_sects && 95 + sector_div(tmp, granularity) != alignment) { 96 + end_sect = end_sect - alignment; 97 + sector_div(end_sect, granularity); 98 + end_sect = end_sect * granularity + alignment; 99 + req_sects = end_sect - sector; 100 + } 86 101 87 102 bio->bi_iter.bi_sector = sector; 88 103 bio->bi_end_io = bio_batch_end_io;