-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 196822 b: refs/heads/master c: f31e7e4 h: refs/heads/master v: v3
- Loading branch information
Dmitry Monakhov
authored and
Jens Axboe
committed
Apr 28, 2010
1 parent
ffcdc37
commit 6a7729a
Showing
4 changed files
with
116 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: f17e232e9237c231daf9f0f4b177c61218bcb2e4 | ||
refs/heads/master: f31e7e4022841c43c53b847b86b1bf97a08b2c94 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Functions related to generic helpers functions | ||
*/ | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/bio.h> | ||
#include <linux/blkdev.h> | ||
#include <linux/scatterlist.h> | ||
|
||
#include "blk.h" | ||
|
||
static void blkdev_discard_end_io(struct bio *bio, int err) | ||
{ | ||
if (err) { | ||
if (err == -EOPNOTSUPP) | ||
set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); | ||
clear_bit(BIO_UPTODATE, &bio->bi_flags); | ||
} | ||
|
||
if (bio->bi_private) | ||
complete(bio->bi_private); | ||
__free_page(bio_page(bio)); | ||
|
||
bio_put(bio); | ||
} | ||
|
||
/** | ||
* blkdev_issue_discard - queue a discard | ||
* @bdev: blockdev to issue discard for | ||
* @sector: start sector | ||
* @nr_sects: number of sectors to discard | ||
* @gfp_mask: memory allocation flags (for bio_alloc) | ||
* @flags: BLKDEV_IFL_* flags to control behaviour | ||
* | ||
* Description: | ||
* Issue a discard request for the sectors in question. | ||
*/ | ||
int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) | ||
{ | ||
DECLARE_COMPLETION_ONSTACK(wait); | ||
struct request_queue *q = bdev_get_queue(bdev); | ||
int type = flags & BLKDEV_IFL_BARRIER ? | ||
DISCARD_BARRIER : DISCARD_NOBARRIER; | ||
struct bio *bio; | ||
struct page *page; | ||
int ret = 0; | ||
|
||
if (!q) | ||
return -ENXIO; | ||
|
||
if (!blk_queue_discard(q)) | ||
return -EOPNOTSUPP; | ||
|
||
while (nr_sects && !ret) { | ||
unsigned int sector_size = q->limits.logical_block_size; | ||
unsigned int max_discard_sectors = | ||
min(q->limits.max_discard_sectors, UINT_MAX >> 9); | ||
|
||
bio = bio_alloc(gfp_mask, 1); | ||
if (!bio) | ||
goto out; | ||
bio->bi_sector = sector; | ||
bio->bi_end_io = blkdev_discard_end_io; | ||
bio->bi_bdev = bdev; | ||
if (flags & BLKDEV_IFL_WAIT) | ||
bio->bi_private = &wait; | ||
|
||
/* | ||
* Add a zeroed one-sector payload as that's what | ||
* our current implementations need. If we'll ever need | ||
* more the interface will need revisiting. | ||
*/ | ||
page = alloc_page(gfp_mask | __GFP_ZERO); | ||
if (!page) | ||
goto out_free_bio; | ||
if (bio_add_pc_page(q, bio, page, sector_size, 0) < sector_size) | ||
goto out_free_page; | ||
|
||
/* | ||
* And override the bio size - the way discard works we | ||
* touch many more blocks on disk than the actual payload | ||
* length. | ||
*/ | ||
if (nr_sects > max_discard_sectors) { | ||
bio->bi_size = max_discard_sectors << 9; | ||
nr_sects -= max_discard_sectors; | ||
sector += max_discard_sectors; | ||
} else { | ||
bio->bi_size = nr_sects << 9; | ||
nr_sects = 0; | ||
} | ||
|
||
bio_get(bio); | ||
submit_bio(type, bio); | ||
|
||
if (flags & BLKDEV_IFL_WAIT) | ||
wait_for_completion(&wait); | ||
|
||
if (bio_flagged(bio, BIO_EOPNOTSUPP)) | ||
ret = -EOPNOTSUPP; | ||
else if (!bio_flagged(bio, BIO_UPTODATE)) | ||
ret = -EIO; | ||
bio_put(bio); | ||
} | ||
return ret; | ||
out_free_page: | ||
__free_page(page); | ||
out_free_bio: | ||
bio_put(bio); | ||
out: | ||
return -ENOMEM; | ||
} | ||
EXPORT_SYMBOL(blkdev_issue_discard); |