diff options
| -rw-r--r-- | block/blk-lib.c | 63 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 2 |
2 files changed, 39 insertions, 26 deletions
diff --git a/block/blk-lib.c b/block/blk-lib.c index 700d248cbde5..ccbce2b2ea05 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c | |||
| @@ -22,45 +22,25 @@ static struct bio *next_bio(struct bio *bio, int rw, unsigned int nr_pages, | |||
| 22 | return new; | 22 | return new; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | /** | 25 | int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, |
| 26 | * blkdev_issue_discard - queue a discard | 26 | sector_t nr_sects, gfp_t gfp_mask, int type, struct bio **biop) |
| 27 | * @bdev: blockdev to issue discard for | ||
| 28 | * @sector: start sector | ||
| 29 | * @nr_sects: number of sectors to discard | ||
| 30 | * @gfp_mask: memory allocation flags (for bio_alloc) | ||
| 31 | * @flags: BLKDEV_IFL_* flags to control behaviour | ||
| 32 | * | ||
| 33 | * Description: | ||
| 34 | * Issue a discard request for the sectors in question. | ||
| 35 | */ | ||
| 36 | int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
| 37 | sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) | ||
| 38 | { | 27 | { |
| 39 | struct request_queue *q = bdev_get_queue(bdev); | 28 | struct request_queue *q = bdev_get_queue(bdev); |
| 40 | int type = REQ_WRITE | REQ_DISCARD; | 29 | struct bio *bio = *biop; |
| 41 | unsigned int granularity; | 30 | unsigned int granularity; |
| 42 | int alignment; | 31 | int alignment; |
| 43 | struct bio *bio = NULL; | ||
| 44 | int ret = 0; | ||
| 45 | struct blk_plug plug; | ||
| 46 | 32 | ||
| 47 | if (!q) | 33 | if (!q) |
| 48 | return -ENXIO; | 34 | return -ENXIO; |
| 49 | |||
| 50 | if (!blk_queue_discard(q)) | 35 | if (!blk_queue_discard(q)) |
| 51 | return -EOPNOTSUPP; | 36 | return -EOPNOTSUPP; |
| 37 | if ((type & REQ_SECURE) && !blk_queue_secdiscard(q)) | ||
| 38 | return -EOPNOTSUPP; | ||
| 52 | 39 | ||
| 53 | /* Zero-sector (unknown) and one-sector granularities are the same. */ | 40 | /* Zero-sector (unknown) and one-sector granularities are the same. */ |
| 54 | granularity = max(q->limits.discard_granularity >> 9, 1U); | 41 | granularity = max(q->limits.discard_granularity >> 9, 1U); |
| 55 | alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; | 42 | alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; |
| 56 | 43 | ||
| 57 | if (flags & BLKDEV_DISCARD_SECURE) { | ||
| 58 | if (!blk_queue_secdiscard(q)) | ||
| 59 | return -EOPNOTSUPP; | ||
| 60 | type |= REQ_SECURE; | ||
| 61 | } | ||
| 62 | |||
| 63 | blk_start_plug(&plug); | ||
| 64 | while (nr_sects) { | 44 | while (nr_sects) { |
| 65 | unsigned int req_sects; | 45 | unsigned int req_sects; |
| 66 | sector_t end_sect, tmp; | 46 | sector_t end_sect, tmp; |
| @@ -98,7 +78,38 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | |||
| 98 | */ | 78 | */ |
| 99 | cond_resched(); | 79 | cond_resched(); |
| 100 | } | 80 | } |
| 101 | if (bio) | 81 | |
| 82 | *biop = bio; | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | EXPORT_SYMBOL(__blkdev_issue_discard); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * blkdev_issue_discard - queue a discard | ||
| 89 | * @bdev: blockdev to issue discard for | ||
| 90 | * @sector: start sector | ||
| 91 | * @nr_sects: number of sectors to discard | ||
| 92 | * @gfp_mask: memory allocation flags (for bio_alloc) | ||
| 93 | * @flags: BLKDEV_IFL_* flags to control behaviour | ||
| 94 | * | ||
| 95 | * Description: | ||
| 96 | * Issue a discard request for the sectors in question. | ||
| 97 | */ | ||
| 98 | int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
| 99 | sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) | ||
| 100 | { | ||
| 101 | int type = REQ_WRITE | REQ_DISCARD; | ||
| 102 | struct bio *bio = NULL; | ||
| 103 | struct blk_plug plug; | ||
| 104 | int ret; | ||
| 105 | |||
| 106 | if (flags & BLKDEV_DISCARD_SECURE) | ||
| 107 | type |= REQ_SECURE; | ||
| 108 | |||
| 109 | blk_start_plug(&plug); | ||
| 110 | ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, type, | ||
| 111 | &bio); | ||
| 112 | if (!ret && bio) | ||
| 102 | ret = submit_bio_wait(type, bio); | 113 | ret = submit_bio_wait(type, bio); |
| 103 | blk_finish_plug(&plug); | 114 | blk_finish_plug(&plug); |
| 104 | 115 | ||
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ba72687c5654..b79131acf6c0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -1131,6 +1131,8 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, | |||
| 1131 | extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); | 1131 | extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); |
| 1132 | extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | 1132 | extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, |
| 1133 | sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); | 1133 | sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); |
| 1134 | extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
| 1135 | sector_t nr_sects, gfp_t gfp_mask, int type, struct bio **biop); | ||
| 1134 | extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, | 1136 | extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, |
| 1135 | sector_t nr_sects, gfp_t gfp_mask, struct page *page); | 1137 | sector_t nr_sects, gfp_t gfp_mask, struct page *page); |
| 1136 | extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, | 1138 | extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, |
