summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/blk-lib.c63
-rw-r--r--include/linux/blkdev.h2
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/** 25int __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 */
36int 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}
85EXPORT_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 */
98int 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,
1131extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); 1131extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *);
1132extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, 1132extern 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);
1134extern 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);
1134extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, 1136extern 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);
1136extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, 1138extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,