diff options
author | Kent Overstreet <kmo@daterainc.com> | 2013-08-07 17:26:21 -0400 |
---|---|---|
committer | Kent Overstreet <kmo@daterainc.com> | 2013-11-24 01:33:49 -0500 |
commit | 4550dd6c6b062fc5e5b647296d55da22616123c3 (patch) | |
tree | 9ca83cc0283151980b7c2f18c0e928aa34a2a0d9 /include | |
parent | 7988613b0e5b2638caf6cd493cc78e9595eba19c (diff) |
block: Immutable bio vecs
This adds a mechanism by which we can advance a bio by an arbitrary
number of bytes without modifying the biovec: bio->bi_iter.bi_bvec_done
indicates the number of bytes completed in the current bvec.
Various driver code still needs to be updated to not refer to the bvec
directly before we can use this for interesting things, like efficient
bio splitting.
Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Lars Ellenberg <drbd-dev@lists.linbit.com>
Cc: Paul Clements <Paul.Clements@steeleye.com>
Cc: drbd-user@lists.linbit.com
Cc: nbd-general@lists.sourceforge.net
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/bio.h | 81 | ||||
-rw-r--r-- | include/linux/blk_types.h | 3 | ||||
-rw-r--r-- | include/linux/blkdev.h | 4 |
3 files changed, 78 insertions, 10 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h index c16adb5f69f8..04e592e74c92 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -64,11 +64,38 @@ | |||
64 | #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) | 64 | #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) |
65 | #define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) | 65 | #define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) |
66 | 66 | ||
67 | #define bio_iter_iovec(bio, iter) ((bio)->bi_io_vec[(iter).bi_idx]) | 67 | #define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) |
68 | 68 | ||
69 | #define bio_page(bio) (bio_iovec((bio)).bv_page) | 69 | #define bvec_iter_page(bvec, iter) \ |
70 | #define bio_offset(bio) (bio_iovec((bio)).bv_offset) | 70 | (__bvec_iter_bvec((bvec), (iter))->bv_page) |
71 | #define bio_iovec(bio) (*__bio_iovec(bio)) | 71 | |
72 | #define bvec_iter_len(bvec, iter) \ | ||
73 | min((iter).bi_size, \ | ||
74 | __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) | ||
75 | |||
76 | #define bvec_iter_offset(bvec, iter) \ | ||
77 | (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) | ||
78 | |||
79 | #define bvec_iter_bvec(bvec, iter) \ | ||
80 | ((struct bio_vec) { \ | ||
81 | .bv_page = bvec_iter_page((bvec), (iter)), \ | ||
82 | .bv_len = bvec_iter_len((bvec), (iter)), \ | ||
83 | .bv_offset = bvec_iter_offset((bvec), (iter)), \ | ||
84 | }) | ||
85 | |||
86 | #define bio_iter_iovec(bio, iter) \ | ||
87 | bvec_iter_bvec((bio)->bi_io_vec, (iter)) | ||
88 | |||
89 | #define bio_iter_page(bio, iter) \ | ||
90 | bvec_iter_page((bio)->bi_io_vec, (iter)) | ||
91 | #define bio_iter_len(bio, iter) \ | ||
92 | bvec_iter_len((bio)->bi_io_vec, (iter)) | ||
93 | #define bio_iter_offset(bio, iter) \ | ||
94 | bvec_iter_offset((bio)->bi_io_vec, (iter)) | ||
95 | |||
96 | #define bio_page(bio) bio_iter_page((bio), (bio)->bi_iter) | ||
97 | #define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) | ||
98 | #define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) | ||
72 | 99 | ||
73 | #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) | 100 | #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) |
74 | #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) | 101 | #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) |
@@ -145,16 +172,54 @@ static inline void *bio_data(struct bio *bio) | |||
145 | bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ | 172 | bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ |
146 | i++) | 173 | i++) |
147 | 174 | ||
175 | static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, | ||
176 | unsigned bytes) | ||
177 | { | ||
178 | WARN_ONCE(bytes > iter->bi_size, | ||
179 | "Attempted to advance past end of bvec iter\n"); | ||
180 | |||
181 | while (bytes) { | ||
182 | unsigned len = min(bytes, bvec_iter_len(bv, *iter)); | ||
183 | |||
184 | bytes -= len; | ||
185 | iter->bi_size -= len; | ||
186 | iter->bi_bvec_done += len; | ||
187 | |||
188 | if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { | ||
189 | iter->bi_bvec_done = 0; | ||
190 | iter->bi_idx++; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | #define for_each_bvec(bvl, bio_vec, iter, start) \ | ||
196 | for ((iter) = start; \ | ||
197 | (bvl) = bvec_iter_bvec((bio_vec), (iter)), \ | ||
198 | (iter).bi_size; \ | ||
199 | bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) | ||
200 | |||
201 | |||
202 | static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, | ||
203 | unsigned bytes) | ||
204 | { | ||
205 | iter->bi_sector += bytes >> 9; | ||
206 | |||
207 | if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) | ||
208 | iter->bi_size -= bytes; | ||
209 | else | ||
210 | bvec_iter_advance(bio->bi_io_vec, iter, bytes); | ||
211 | } | ||
212 | |||
148 | #define __bio_for_each_segment(bvl, bio, iter, start) \ | 213 | #define __bio_for_each_segment(bvl, bio, iter, start) \ |
149 | for (iter = (start); \ | 214 | for (iter = (start); \ |
150 | bvl = bio_iter_iovec((bio), (iter)), \ | 215 | (iter).bi_size && \ |
151 | (iter).bi_idx < (bio)->bi_vcnt; \ | 216 | ((bvl = bio_iter_iovec((bio), (iter))), 1); \ |
152 | (iter).bi_idx++) | 217 | bio_advance_iter((bio), &(iter), (bvl).bv_len)) |
153 | 218 | ||
154 | #define bio_for_each_segment(bvl, bio, iter) \ | 219 | #define bio_for_each_segment(bvl, bio, iter) \ |
155 | __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) | 220 | __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) |
156 | 221 | ||
157 | #define bio_iter_last(bio, iter) ((iter).bi_idx == (bio)->bi_vcnt - 1) | 222 | #define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) |
158 | 223 | ||
159 | /* | 224 | /* |
160 | * get a reference to a bio, so it won't disappear. the intended use is | 225 | * get a reference to a bio, so it won't disappear. the intended use is |
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 29b5b84d8a29..d369f8f6af79 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h | |||
@@ -34,6 +34,9 @@ struct bvec_iter { | |||
34 | unsigned int bi_size; /* residual I/O count */ | 34 | unsigned int bi_size; /* residual I/O count */ |
35 | 35 | ||
36 | unsigned int bi_idx; /* current index into bvl_vec */ | 36 | unsigned int bi_idx; /* current index into bvl_vec */ |
37 | |||
38 | unsigned int bi_bvec_done; /* number of bytes completed in | ||
39 | current bvec */ | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | /* | 42 | /* |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 337b92a54658..02cb6f0ea71d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -750,9 +750,9 @@ struct req_iterator { | |||
750 | __rq_for_each_bio(_iter.bio, _rq) \ | 750 | __rq_for_each_bio(_iter.bio, _rq) \ |
751 | bio_for_each_segment(bvl, _iter.bio, _iter.iter) | 751 | bio_for_each_segment(bvl, _iter.bio, _iter.iter) |
752 | 752 | ||
753 | #define rq_iter_last(rq, _iter) \ | 753 | #define rq_iter_last(bvec, _iter) \ |
754 | (_iter.bio->bi_next == NULL && \ | 754 | (_iter.bio->bi_next == NULL && \ |
755 | bio_iter_last(_iter.bio, _iter.iter)) | 755 | bio_iter_last(bvec, _iter.iter)) |
756 | 756 | ||
757 | #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE | 757 | #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE |
758 | # error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" | 758 | # error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" |