aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-barrier.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-08-05 13:01:53 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:01 -0400
commitfb2dce862d9f9a68e6b9374579056ec9eca02a63 (patch)
tree888e0fd7248c9329fa1aa3981043a2dc2457d488 /block/blk-barrier.c
parentd628eaef310533767ce68664873869c2d7f78f09 (diff)
Add 'discard' request handling
Some block devices benefit from a hint that they can forget the contents of certain sectors. Add basic support for this to the block core, along with a 'blkdev_issue_discard()' helper function which issues such requests. The caller doesn't get to provide an end_io functio, since blkdev_issue_discard() will automatically split the request up into multiple bios if appropriate. Neither does the function wait for completion -- it's expected that callers won't care about when, or even _if_, the request completes. It's only a hint to the device anyway. By definition, the file system doesn't _care_ about these sectors any more. [With feedback from OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> and Jens Axboe <jens.axboe@oracle.com] Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/blk-barrier.c')
-rw-r--r--block/blk-barrier.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index a09ead19f9c5..273121c0eb80 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -315,3 +315,72 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
315 return ret; 315 return ret;
316} 316}
317EXPORT_SYMBOL(blkdev_issue_flush); 317EXPORT_SYMBOL(blkdev_issue_flush);
318
319static void blkdev_discard_end_io(struct bio *bio, int err)
320{
321 if (err) {
322 if (err == -EOPNOTSUPP)
323 set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
324 clear_bit(BIO_UPTODATE, &bio->bi_flags);
325 }
326
327 bio_put(bio);
328}
329
330/**
331 * blkdev_issue_discard - queue a discard
332 * @bdev: blockdev to issue discard for
333 * @sector: start sector
334 * @nr_sects: number of sectors to discard
335 *
336 * Description:
337 * Issue a discard request for the sectors in question. Does not wait.
338 */
339int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
340 unsigned nr_sects)
341{
342 struct request_queue *q;
343 struct bio *bio;
344 int ret = 0;
345
346 if (bdev->bd_disk == NULL)
347 return -ENXIO;
348
349 q = bdev_get_queue(bdev);
350 if (!q)
351 return -ENXIO;
352
353 if (!q->prepare_discard_fn)
354 return -EOPNOTSUPP;
355
356 while (nr_sects && !ret) {
357 bio = bio_alloc(GFP_KERNEL, 0);
358 if (!bio)
359 return -ENOMEM;
360
361 bio->bi_end_io = blkdev_discard_end_io;
362 bio->bi_bdev = bdev;
363
364 bio->bi_sector = sector;
365
366 if (nr_sects > q->max_hw_sectors) {
367 bio->bi_size = q->max_hw_sectors << 9;
368 nr_sects -= q->max_hw_sectors;
369 sector += q->max_hw_sectors;
370 } else {
371 bio->bi_size = nr_sects << 9;
372 nr_sects = 0;
373 }
374 bio_get(bio);
375 submit_bio(WRITE_DISCARD, bio);
376
377 /* Check if it failed immediately */
378 if (bio_flagged(bio, BIO_EOPNOTSUPP))
379 ret = -EOPNOTSUPP;
380 else if (!bio_flagged(bio, BIO_UPTODATE))
381 ret = -EIO;
382 bio_put(bio);
383 }
384 return ret;
385}
386EXPORT_SYMBOL(blkdev_issue_discard);