aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/blk-lib.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 0dc438812d81..886c3f9e1be4 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -112,3 +112,121 @@ out:
112 return -ENOMEM; 112 return -ENOMEM;
113} 113}
114EXPORT_SYMBOL(blkdev_issue_discard); 114EXPORT_SYMBOL(blkdev_issue_discard);
115
116struct bio_batch
117{
118 atomic_t done;
119 unsigned long flags;
120 struct completion *wait;
121 bio_end_io_t *end_io;
122};
123
124static void bio_batch_end_io(struct bio *bio, int err)
125{
126 struct bio_batch *bb = bio->bi_private;
127 if (err) {
128 if (err == -EOPNOTSUPP)
129 set_bit(BIO_EOPNOTSUPP, &bb->flags);
130 else
131 clear_bit(BIO_UPTODATE, &bb->flags);
132 }
133 if (bb) {
134 if (bb->end_io)
135 bb->end_io(bio, err);
136 atomic_inc(&bb->done);
137 complete(bb->wait);
138 }
139 bio_put(bio);
140}
141
142/**
143 * blkdev_issue_zeroout generate number of zero filed write bios
144 * @bdev: blockdev to issue
145 * @sector: start sector
146 * @nr_sects: number of sectors to write
147 * @gfp_mask: memory allocation flags (for bio_alloc)
148 * @flags: BLKDEV_IFL_* flags to control behaviour
149 *
150 * Description:
151 * Generate and issue number of bios with zerofiled pages.
152 * Send barrier at the beginning and at the end if requested. This guarantie
153 * correct request ordering. Empty barrier allow us to avoid post queue flush.
154 */
155
156int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
157 sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
158{
159 int ret = 0;
160 struct bio *bio;
161 struct bio_batch bb;
162 unsigned int sz, issued = 0;
163 DECLARE_COMPLETION_ONSTACK(wait);
164
165 atomic_set(&bb.done, 0);
166 bb.flags = 1 << BIO_UPTODATE;
167 bb.wait = &wait;
168 bb.end_io = NULL;
169
170 if (flags & BLKDEV_IFL_BARRIER) {
171 /* issue async barrier before the data */
172 ret = blkdev_issue_flush(bdev, gfp_mask, NULL, 0);
173 if (ret)
174 return ret;
175 }
176submit:
177 while (nr_sects != 0) {
178 bio = bio_alloc(gfp_mask,
179 min(nr_sects, (sector_t)BIO_MAX_PAGES));
180 if (!bio)
181 break;
182
183 bio->bi_sector = sector;
184 bio->bi_bdev = bdev;
185 bio->bi_end_io = bio_batch_end_io;
186 if (flags & BLKDEV_IFL_WAIT)
187 bio->bi_private = &bb;
188
189 while(nr_sects != 0) {
190 sz = min(PAGE_SIZE >> 9 , nr_sects);
191 if (sz == 0)
192 /* bio has maximum size possible */
193 break;
194 ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
195 nr_sects -= ret >> 9;
196 sector += ret >> 9;
197 if (ret < (sz << 9))
198 break;
199 }
200 issued++;
201 submit_bio(WRITE, bio);
202 }
203 /*
204 * When all data bios are in flight. Send final barrier if requeted.
205 */
206 if (nr_sects == 0 && flags & BLKDEV_IFL_BARRIER)
207 ret = blkdev_issue_flush(bdev, gfp_mask, NULL,
208 flags & BLKDEV_IFL_WAIT);
209
210
211 if (flags & BLKDEV_IFL_WAIT)
212 /* Wait for bios in-flight */
213 while ( issued != atomic_read(&bb.done))
214 wait_for_completion(&wait);
215
216 if (!test_bit(BIO_UPTODATE, &bb.flags))
217 /* One of bios in the batch was completed with error.*/
218 ret = -EIO;
219
220 if (ret)
221 goto out;
222
223 if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
224 ret = -EOPNOTSUPP;
225 goto out;
226 }
227 if (nr_sects != 0)
228 goto submit;
229out:
230 return ret;
231}
232EXPORT_SYMBOL(blkdev_issue_zeroout);