diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-08-05 13:01:53 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:01 -0400 |
commit | fb2dce862d9f9a68e6b9374579056ec9eca02a63 (patch) | |
tree | 888e0fd7248c9329fa1aa3981043a2dc2457d488 /include | |
parent | d628eaef310533767ce68664873869c2d7f78f09 (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 'include')
-rw-r--r-- | include/linux/bio.h | 8 | ||||
-rw-r--r-- | include/linux/blkdev.h | 16 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
3 files changed, 24 insertions, 3 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h index 17f1fbdb31bf..1fdfc5621c83 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -149,6 +149,8 @@ struct bio { | |||
149 | * bit 2 -- barrier | 149 | * bit 2 -- barrier |
150 | * bit 3 -- fail fast, don't want low level driver retries | 150 | * bit 3 -- fail fast, don't want low level driver retries |
151 | * bit 4 -- synchronous I/O hint: the block layer will unplug immediately | 151 | * bit 4 -- synchronous I/O hint: the block layer will unplug immediately |
152 | * bit 5 -- metadata request | ||
153 | * bit 6 -- discard sectors | ||
152 | */ | 154 | */ |
153 | #define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */ | 155 | #define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */ |
154 | #define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */ | 156 | #define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */ |
@@ -156,6 +158,7 @@ struct bio { | |||
156 | #define BIO_RW_FAILFAST 3 | 158 | #define BIO_RW_FAILFAST 3 |
157 | #define BIO_RW_SYNC 4 | 159 | #define BIO_RW_SYNC 4 |
158 | #define BIO_RW_META 5 | 160 | #define BIO_RW_META 5 |
161 | #define BIO_RW_DISCARD 6 | ||
159 | 162 | ||
160 | /* | 163 | /* |
161 | * upper 16 bits of bi_rw define the io priority of this bio | 164 | * upper 16 bits of bi_rw define the io priority of this bio |
@@ -186,13 +189,14 @@ struct bio { | |||
186 | #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) | 189 | #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) |
187 | #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) | 190 | #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) |
188 | #define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio)) | 191 | #define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio)) |
192 | #define bio_discard(bio) ((bio)->bi_rw & (1 << BIO_RW_DISCARD)) | ||
189 | 193 | ||
190 | static inline unsigned int bio_cur_sectors(struct bio *bio) | 194 | static inline unsigned int bio_cur_sectors(struct bio *bio) |
191 | { | 195 | { |
192 | if (bio->bi_vcnt) | 196 | if (bio->bi_vcnt) |
193 | return bio_iovec(bio)->bv_len >> 9; | 197 | return bio_iovec(bio)->bv_len >> 9; |
194 | 198 | else /* dataless requests such as discard */ | |
195 | return 0; | 199 | return bio->bi_size >> 9; |
196 | } | 200 | } |
197 | 201 | ||
198 | static inline void *bio_data(struct bio *bio) | 202 | static inline void *bio_data(struct bio *bio) |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index e0ba018f5e88..26ececbbebe2 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -89,6 +89,7 @@ enum { | |||
89 | enum rq_flag_bits { | 89 | enum rq_flag_bits { |
90 | __REQ_RW, /* not set, read. set, write */ | 90 | __REQ_RW, /* not set, read. set, write */ |
91 | __REQ_FAILFAST, /* no low level driver retries */ | 91 | __REQ_FAILFAST, /* no low level driver retries */ |
92 | __REQ_DISCARD, /* request to discard sectors */ | ||
92 | __REQ_SORTED, /* elevator knows about this request */ | 93 | __REQ_SORTED, /* elevator knows about this request */ |
93 | __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ | 94 | __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ |
94 | __REQ_HARDBARRIER, /* may not be passed by drive either */ | 95 | __REQ_HARDBARRIER, /* may not be passed by drive either */ |
@@ -111,6 +112,7 @@ enum rq_flag_bits { | |||
111 | }; | 112 | }; |
112 | 113 | ||
113 | #define REQ_RW (1 << __REQ_RW) | 114 | #define REQ_RW (1 << __REQ_RW) |
115 | #define REQ_DISCARD (1 << __REQ_DISCARD) | ||
114 | #define REQ_FAILFAST (1 << __REQ_FAILFAST) | 116 | #define REQ_FAILFAST (1 << __REQ_FAILFAST) |
115 | #define REQ_SORTED (1 << __REQ_SORTED) | 117 | #define REQ_SORTED (1 << __REQ_SORTED) |
116 | #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) | 118 | #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) |
@@ -252,6 +254,7 @@ typedef void (request_fn_proc) (struct request_queue *q); | |||
252 | typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); | 254 | typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); |
253 | typedef int (prep_rq_fn) (struct request_queue *, struct request *); | 255 | typedef int (prep_rq_fn) (struct request_queue *, struct request *); |
254 | typedef void (unplug_fn) (struct request_queue *); | 256 | typedef void (unplug_fn) (struct request_queue *); |
257 | typedef int (prepare_discard_fn) (struct request_queue *, struct request *); | ||
255 | 258 | ||
256 | struct bio_vec; | 259 | struct bio_vec; |
257 | struct bvec_merge_data { | 260 | struct bvec_merge_data { |
@@ -307,6 +310,7 @@ struct request_queue | |||
307 | make_request_fn *make_request_fn; | 310 | make_request_fn *make_request_fn; |
308 | prep_rq_fn *prep_rq_fn; | 311 | prep_rq_fn *prep_rq_fn; |
309 | unplug_fn *unplug_fn; | 312 | unplug_fn *unplug_fn; |
313 | prepare_discard_fn *prepare_discard_fn; | ||
310 | merge_bvec_fn *merge_bvec_fn; | 314 | merge_bvec_fn *merge_bvec_fn; |
311 | prepare_flush_fn *prepare_flush_fn; | 315 | prepare_flush_fn *prepare_flush_fn; |
312 | softirq_done_fn *softirq_done_fn; | 316 | softirq_done_fn *softirq_done_fn; |
@@ -546,6 +550,7 @@ enum { | |||
546 | #define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED) | 550 | #define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED) |
547 | #define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER) | 551 | #define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER) |
548 | #define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA) | 552 | #define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA) |
553 | #define blk_discard_rq(rq) ((rq)->cmd_flags & REQ_DISCARD) | ||
549 | #define blk_bidi_rq(rq) ((rq)->next_rq != NULL) | 554 | #define blk_bidi_rq(rq) ((rq)->next_rq != NULL) |
550 | #define blk_empty_barrier(rq) (blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors) | 555 | #define blk_empty_barrier(rq) (blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors) |
551 | /* rq->queuelist of dequeued request must be list_empty() */ | 556 | /* rq->queuelist of dequeued request must be list_empty() */ |
@@ -796,6 +801,7 @@ extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *); | |||
796 | extern void blk_queue_dma_alignment(struct request_queue *, int); | 801 | extern void blk_queue_dma_alignment(struct request_queue *, int); |
797 | extern void blk_queue_update_dma_alignment(struct request_queue *, int); | 802 | extern void blk_queue_update_dma_alignment(struct request_queue *, int); |
798 | extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); | 803 | extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); |
804 | extern void blk_queue_set_discard(struct request_queue *, prepare_discard_fn *); | ||
799 | extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); | 805 | extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); |
800 | extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *); | 806 | extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *); |
801 | extern int blk_do_ordered(struct request_queue *, struct request **); | 807 | extern int blk_do_ordered(struct request_queue *, struct request **); |
@@ -837,6 +843,16 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, | |||
837 | } | 843 | } |
838 | 844 | ||
839 | extern int blkdev_issue_flush(struct block_device *, sector_t *); | 845 | extern int blkdev_issue_flush(struct block_device *, sector_t *); |
846 | extern int blkdev_issue_discard(struct block_device *, sector_t sector, | ||
847 | unsigned nr_sects); | ||
848 | |||
849 | static inline int sb_issue_discard(struct super_block *sb, | ||
850 | sector_t block, unsigned nr_blocks) | ||
851 | { | ||
852 | block <<= (sb->s_blocksize_bits - 9); | ||
853 | nr_blocks <<= (sb->s_blocksize_bits - 9); | ||
854 | return blkdev_issue_discard(sb->s_bdev, block, nr_blocks); | ||
855 | } | ||
840 | 856 | ||
841 | /* | 857 | /* |
842 | * command filter functions | 858 | * command filter functions |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 580b513668fe..eb0131319134 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -86,7 +86,8 @@ extern int dir_notify_enable; | |||
86 | #define READ_META (READ | (1 << BIO_RW_META)) | 86 | #define READ_META (READ | (1 << BIO_RW_META)) |
87 | #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) | 87 | #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) |
88 | #define SWRITE_SYNC (SWRITE | (1 << BIO_RW_SYNC)) | 88 | #define SWRITE_SYNC (SWRITE | (1 << BIO_RW_SYNC)) |
89 | #define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) | 89 | #define WRITE_BARRIER (WRITE | (1 << BIO_RW_BARRIER)) |
90 | #define WRITE_DISCARD (WRITE | (1 << BIO_RW_DISCARD)) | ||
90 | 91 | ||
91 | #define SEL_IN 1 | 92 | #define SEL_IN 1 |
92 | #define SEL_OUT 2 | 93 | #define SEL_OUT 2 |