forked from torvalds/linux
-
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.
blkdev: move blkdev_issue helper functions to separate file
Move blkdev_issue_discard from blk-barrier.c because it is not barrier related. Later the file will be populated by other helpers. Signed-off-by: Dmitry Monakhov <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
- Loading branch information
Dmitry Monakhov
authored and
Jens Axboe
committed
Apr 28, 2010
1 parent
f17e232
commit f31e7e4
Showing
3 changed files
with
115 additions
and
105 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
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); |