add patch implement-cgroup-writeback-support
[ext4-patch-queue.git] / use-discard-if-possible-in-blkdev_issue_zeroout
blob2bd9147b698ae1e9a56f4939c3d3ddbc53c42daf
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>
8 ---
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
14 --- a/block/blk-lib.c
15 +++ b/block/blk-lib.c
16 @@ -269,6 +269,32 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
17         return ret;
18  }
20 +static int issue_zeroout_or_write_same(struct block_device *bdev,
21 +                                      sector_t sector,
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,
28 +                                            ZERO_PAGE(0)))
29 +                       return 0;
31 +               bdevname(bdev, bdn);
32 +               pr_err("%s: WRITE SAME failed. Manually zeroing.\n", bdn);
33 +       }
35 +       return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
38 +/*
39 + * Like sector_div except don't modify s.
40 + */
41 +static unsigned int sector_mod(sector_t s, unsigned int m)
43 +       return sector_div(s, m);
46  /**
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)
51   *
52   * Description:
53 - *  Generate and issue number of bios with zerofiled pages.
54 + *  Issues bios which zeros the requested block range.
55   */
57  int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
58                          sector_t nr_sects, gfp_t gfp_mask)
59  {
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;
64 +       unsigned int c;
65 +       int ret;
67 -               if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask,
68 -                                            ZERO_PAGE(0)))
69 -                       return 0;
70 +       if (!q)
71 +               return -ENXIO;
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);
85 +       if (c > nr_sects)
86 +               c = nr_sects;
88 +       if (c) {
89 +               int ret = issue_zeroout_or_write_same(bdev, sector,
90 +                                                     c, gfp_mask);
91 +               if (ret)
92 +                       return ret;
93 +               nr_sects -= c;
94         }
95 +       if (nr_sects == 0)
96 +               return 0;
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);
102 +       if (ret || c == 0)
103 +               return ret;
105 +       return issue_zeroout_or_write_same(bdev, sector + nr_sects - c, c,
106 +                                          gfp_mask);
108  EXPORT_SYMBOL(blkdev_issue_zeroout);