1 block: use discard if possible in blkdev_issue_zeroout()
3 If the block device supports discards and guarantees that subsequent
4 reads will return zeros (sometimes known as DZAT, for Deterministic
5 read Zeros After Trim), use this to implement blkdev_issue_zeroout()
7 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
9 block/blk-lib.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
10 1 file changed, 62 insertions(+), 10 deletions(-)
12 diff --git a/block/blk-lib.c b/block/blk-lib.c
13 index 2da76c9..62cbf28 100644
16 @@ -269,6 +269,32 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
20 +static int issue_zeroout_or_write_same(struct block_device *bdev,
22 + sector_t nr_sects, gfp_t gfp_mask)
24 + if (bdev_write_same(bdev)) {
25 + unsigned char bdn[BDEVNAME_SIZE];
27 + if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask,
31 + bdevname(bdev, bdn);
32 + pr_err("%s: WRITE SAME failed. Manually zeroing.\n", bdn);
35 + return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
39 + * Like sector_div except don't modify s.
41 +static unsigned int sector_mod(sector_t s, unsigned int m)
43 + return sector_div(s, m);
47 * blkdev_issue_zeroout - zero-fill a block range
48 * @bdev: blockdev to write
49 @@ -277,23 +303,49 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
50 * @gfp_mask: memory allocation flags (for bio_alloc)
53 - * Generate and issue number of bios with zerofiled pages.
54 + * Issues bios which zeros the requested block range.
57 int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
58 sector_t nr_sects, gfp_t gfp_mask)
60 - if (bdev_write_same(bdev)) {
61 - unsigned char bdn[BDEVNAME_SIZE];
62 + struct request_queue *q = bdev_get_queue(bdev);
63 + unsigned int alignment, granularity;
67 - if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask,
73 - bdevname(bdev, bdn);
74 - pr_err("%s: WRITE SAME failed. Manually zeroing.\n", bdn);
75 + if (!blk_queue_discard(q) || !queue_discard_zeroes_data(q) ||
76 + q->limits.discard_misaligned)
77 + return issue_zeroout_or_write_same(bdev, sector,
79 + nr_sects, gfp_mask);
81 + alignment = q->limits.discard_alignment >> 9;
82 + granularity = q->limits.discard_granularity >> 9;
84 + c = sector_mod(granularity + alignment - sector, granularity);
89 + int ret = issue_zeroout_or_write_same(bdev, sector,
98 - return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
99 + c = sector_mod(nr_sects, granularity);
101 + ret = blkdev_issue_discard(bdev, sector, nr_sects - c, gfp_mask, 0);
105 + return issue_zeroout_or_write_same(bdev, sector + nr_sects - c, c,
108 EXPORT_SYMBOL(blkdev_issue_zeroout);