aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-lib.c
diff options
context:
space:
mode:
authorMing Lin <ming.l@ssi.samsung.com>2015-10-22 12:59:42 -0400
committerJens Axboe <axboe@fb.com>2015-10-27 20:12:58 -0400
commita22c4d7e34402ccdf3414f64c50365436eba7b93 (patch)
tree2d71db7c04930b5f88f4745cb6c8d5c59cf33075 /block/blk-lib.c
parent23d88271b4f97f66de521ac9b2c1471e6311cf26 (diff)
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>
Diffstat (limited to 'block/blk-lib.c')
-rw-r--r--block/blk-lib.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/block/blk-lib.c b/block/blk-lib.c
index bd40292e5009..9ebf65379556 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -26,13 +26,6 @@ static void bio_batch_end_io(struct bio *bio)
26 bio_put(bio); 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 * blkdev_issue_discard - queue a discard 30 * blkdev_issue_discard - queue a discard
38 * @bdev: blockdev to issue discard for 31 * @bdev: blockdev to issue discard for
@@ -50,6 +43,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
50 DECLARE_COMPLETION_ONSTACK(wait); 43 DECLARE_COMPLETION_ONSTACK(wait);
51 struct request_queue *q = bdev_get_queue(bdev); 44 struct request_queue *q = bdev_get_queue(bdev);
52 int type = REQ_WRITE | REQ_DISCARD; 45 int type = REQ_WRITE | REQ_DISCARD;
46 unsigned int granularity;
47 int alignment;
53 struct bio_batch bb; 48 struct bio_batch bb;
54 struct bio *bio; 49 struct bio *bio;
55 int ret = 0; 50 int ret = 0;
@@ -61,6 +56,10 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
61 if (!blk_queue_discard(q)) 56 if (!blk_queue_discard(q))
62 return -EOPNOTSUPP; 57 return -EOPNOTSUPP;
63 58
59 /* Zero-sector (unknown) and one-sector granularities are the same. */
60 granularity = max(q->limits.discard_granularity >> 9, 1U);
61 alignment = (bdev_discard_alignment(bdev) >> 9) % granularity;
62
64 if (flags & BLKDEV_DISCARD_SECURE) { 63 if (flags & BLKDEV_DISCARD_SECURE) {
65 if (!blk_queue_secdiscard(q)) 64 if (!blk_queue_secdiscard(q))
66 return -EOPNOTSUPP; 65 return -EOPNOTSUPP;
@@ -74,7 +73,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
74 blk_start_plug(&plug); 73 blk_start_plug(&plug);
75 while (nr_sects) { 74 while (nr_sects) {
76 unsigned int req_sects; 75 unsigned int req_sects;
77 sector_t end_sect; 76 sector_t end_sect, tmp;
78 77
79 bio = bio_alloc(gfp_mask, 1); 78 bio = bio_alloc(gfp_mask, 1);
80 if (!bio) { 79 if (!bio) {
@@ -82,8 +81,22 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
82 break; 81 break;
83 } 82 }
84 83
85 req_sects = min_t(sector_t, nr_sects, MAX_BIO_SECTORS); 84 /* Make sure bi_size doesn't overflow */
85 req_sects = min_t(sector_t, nr_sects, UINT_MAX >> 9);
86
87 /*
88 * If splitting a request, and the next starting sector would be
89 * misaligned, stop the discard at the previous aligned sector.
90 */
86 end_sect = sector + req_sects; 91 end_sect = sector + req_sects;
92 tmp = end_sect;
93 if (req_sects < nr_sects &&
94 sector_div(tmp, granularity) != alignment) {
95 end_sect = end_sect - alignment;
96 sector_div(end_sect, granularity);
97 end_sect = end_sect * granularity + alignment;
98 req_sects = end_sect - sector;
99 }
87 100
88 bio->bi_iter.bi_sector = sector; 101 bio->bi_iter.bi_sector = sector;
89 bio->bi_end_io = bio_batch_end_io; 102 bio->bi_end_io = bio_batch_end_io;