diff options
author | Ming Lin <ming.l@ssi.samsung.com> | 2015-10-22 12:59:42 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-10-27 20:12:58 -0400 |
commit | a22c4d7e34402ccdf3414f64c50365436eba7b93 (patch) | |
tree | 2d71db7c04930b5f88f4745cb6c8d5c59cf33075 /block/blk-lib.c | |
parent | 23d88271b4f97f66de521ac9b2c1471e6311cf26 (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.c | 31 |
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; |