]> git.karo-electronics.de Git - karo-tx-linux.git/blob - block/blk-lib.c
blkdev: Submit discard bio in batches in blkdev_issue_discard()
[karo-tx-linux.git] / block / blk-lib.c
1 /*
2  * Functions related to generic helpers functions
3  */
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/bio.h>
7 #include <linux/blkdev.h>
8 #include <linux/scatterlist.h>
9
10 #include "blk.h"
11
12 struct bio_batch {
13         atomic_t                done;
14         unsigned long           flags;
15         struct completion       *wait;
16 };
17
18 static void bio_batch_end_io(struct bio *bio, int err)
19 {
20         struct bio_batch *bb = bio->bi_private;
21
22         if (err) {
23                 if (err == -EOPNOTSUPP)
24                         set_bit(BIO_EOPNOTSUPP, &bb->flags);
25                 clear_bit(BIO_UPTODATE, &bb->flags);
26         }
27         if (atomic_dec_and_test(&bb->done))
28                 complete(bb->wait);
29         bio_put(bio);
30 }
31
32 /**
33  * blkdev_issue_discard - queue a discard
34  * @bdev:       blockdev to issue discard for
35  * @sector:     start sector
36  * @nr_sects:   number of sectors to discard
37  * @gfp_mask:   memory allocation flags (for bio_alloc)
38  * @flags:      BLKDEV_IFL_* flags to control behaviour
39  *
40  * Description:
41  *    Issue a discard request for the sectors in question.
42  */
43 int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
44                 sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
45 {
46         DECLARE_COMPLETION_ONSTACK(wait);
47         struct request_queue *q = bdev_get_queue(bdev);
48         int type = REQ_WRITE | REQ_DISCARD;
49         unsigned int max_discard_sectors;
50         struct bio_batch bb;
51         struct bio *bio;
52         int ret = 0;
53
54         if (!q)
55                 return -ENXIO;
56
57         if (!blk_queue_discard(q))
58                 return -EOPNOTSUPP;
59
60         /*
61          * Ensure that max_discard_sectors is of the proper
62          * granularity
63          */
64         max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
65         if (q->limits.discard_granularity) {
66                 unsigned int disc_sects = q->limits.discard_granularity >> 9;
67
68                 max_discard_sectors &= ~(disc_sects - 1);
69         }
70
71         if (flags & BLKDEV_DISCARD_SECURE) {
72                 if (!blk_queue_secdiscard(q))
73                         return -EOPNOTSUPP;
74                 type |= REQ_SECURE;
75         }
76
77         atomic_set(&bb.done, 1);
78         bb.flags = 1 << BIO_UPTODATE;
79         bb.wait = &wait;
80
81         while (nr_sects) {
82                 bio = bio_alloc(gfp_mask, 1);
83                 if (!bio) {
84                         ret = -ENOMEM;
85                         break;
86                 }
87
88                 bio->bi_sector = sector;
89                 bio->bi_end_io = bio_batch_end_io;
90                 bio->bi_bdev = bdev;
91                 bio->bi_private = &bb;
92
93                 if (nr_sects > max_discard_sectors) {
94                         bio->bi_size = max_discard_sectors << 9;
95                         nr_sects -= max_discard_sectors;
96                         sector += max_discard_sectors;
97                 } else {
98                         bio->bi_size = nr_sects << 9;
99                         nr_sects = 0;
100                 }
101
102                 atomic_inc(&bb.done);
103                 submit_bio(type, bio);
104         }
105
106         /* Wait for bios in-flight */
107         if (!atomic_dec_and_test(&bb.done))
108                 wait_for_completion(&wait);
109
110         if (test_bit(BIO_EOPNOTSUPP, &bb.flags))
111                 ret = -EOPNOTSUPP;
112         else if (!test_bit(BIO_UPTODATE, &bb.flags))
113                 ret = -EIO;
114
115         return ret;
116 }
117 EXPORT_SYMBOL(blkdev_issue_discard);
118
119 /**
120  * blkdev_issue_zeroout - generate number of zero filed write bios
121  * @bdev:       blockdev to issue
122  * @sector:     start sector
123  * @nr_sects:   number of sectors to write
124  * @gfp_mask:   memory allocation flags (for bio_alloc)
125  *
126  * Description:
127  *  Generate and issue number of bios with zerofiled pages.
128  */
129
130 int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
131                         sector_t nr_sects, gfp_t gfp_mask)
132 {
133         int ret;
134         struct bio *bio;
135         struct bio_batch bb;
136         unsigned int sz;
137         DECLARE_COMPLETION_ONSTACK(wait);
138
139         atomic_set(&bb.done, 1);
140         bb.flags = 1 << BIO_UPTODATE;
141         bb.wait = &wait;
142
143 submit:
144         ret = 0;
145         while (nr_sects != 0) {
146                 bio = bio_alloc(gfp_mask,
147                                 min(nr_sects, (sector_t)BIO_MAX_PAGES));
148                 if (!bio) {
149                         ret = -ENOMEM;
150                         break;
151                 }
152
153                 bio->bi_sector = sector;
154                 bio->bi_bdev   = bdev;
155                 bio->bi_end_io = bio_batch_end_io;
156                 bio->bi_private = &bb;
157
158                 while (nr_sects != 0) {
159                         sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
160                         if (sz == 0)
161                                 /* bio has maximum size possible */
162                                 break;
163                         ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
164                         nr_sects -= ret >> 9;
165                         sector += ret >> 9;
166                         if (ret < (sz << 9))
167                                 break;
168                 }
169                 ret = 0;
170                 atomic_inc(&bb.done);
171                 submit_bio(WRITE, bio);
172         }
173
174         /* Wait for bios in-flight */
175         if (!atomic_dec_and_test(&bb.done))
176                 wait_for_completion(&wait);
177
178         if (!test_bit(BIO_UPTODATE, &bb.flags))
179                 /* One of bios in the batch was completed with error.*/
180                 ret = -EIO;
181
182         if (ret)
183                 goto out;
184
185         if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
186                 ret = -EOPNOTSUPP;
187                 goto out;
188         }
189         if (nr_sects != 0)
190                 goto submit;
191 out:
192         return ret;
193 }
194 EXPORT_SYMBOL(blkdev_issue_zeroout);