This patch introduces bio_for_each_chunk_all() and bio_for_each_chunk_segment_all(), which are for replacing the current bio_for_each_segment_all(). bio_for_each_chunk_all() will iterate one chunk by chunk, which is multipage based. bio_for_each_chunk_segment_all() will iterate one segment by segment, which is singlepage based. For using bio_for_each_chunk_segment_all(), one 24-bytes extra local variable has to be introduced. Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- include/linux/bio.h | 13 +++++++++++++ include/linux/bvec.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/linux/bio.h b/include/linux/bio.h index 0fa1035dde38..f21384be9b51 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -168,6 +168,19 @@ static inline bool bio_full(struct bio *bio) #define bio_for_each_segment_all(bvl, bio, i) \ for (i = 0, bvl = (bio)->bi_io_vec; i < (bio)->bi_vcnt; i++, bvl++) +#define bio_for_each_chunk_all(bvl, bio, i) \ + bio_for_each_segment_all(bvl, bio, i) + +#define chunk_for_each_segment(bv, bvl, i, citer) \ + for (bv = bvec_init_chunk_iter(&citer); \ + (citer.done < (bvl)->bv_len) && \ + ((chunk_next_segment((bvl), &citer)), 1); \ + citer.done += bv->bv_len, i += 1) + +#define bio_for_each_chunk_segment_all(bvl, bio, i, citer) \ + for (i = 0, citer.idx = 0; citer.idx < (bio)->bi_vcnt; citer.idx++) \ + chunk_for_each_segment(bvl, &((bio)->bi_io_vec[citer.idx]), i, citer) + static inline void __bio_advance_iter(struct bio *bio, struct bvec_iter *iter, unsigned bytes, bool chunk) { diff --git a/include/linux/bvec.h b/include/linux/bvec.h index aac75d87d884..d4eaa0c26bb5 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -84,6 +84,12 @@ struct bvec_iter { current bvec */ }; +struct bvec_chunk_iter { + struct bio_vec bv; + int idx; + unsigned done; +}; + /* * various member access, note that bio_data should of course not be used * on highmem page vectors @@ -219,6 +225,31 @@ static inline bool bvec_iter_chunk_advance(const struct bio_vec *bv, .bi_bvec_done = 0, \ } +static inline struct bio_vec *bvec_init_chunk_iter(struct bvec_chunk_iter *citer) +{ + citer->bv.bv_page = NULL; + citer->done = 0; + + return &citer->bv; +} + +/* used for chunk_for_each_segment */ +static inline void chunk_next_segment(const struct bio_vec *chunk, + struct bvec_chunk_iter *iter) +{ + struct bio_vec *bv = &iter->bv; + + if (bv->bv_page) { + bv->bv_page += 1; + bv->bv_offset = 0; + } else { + bv->bv_page = chunk->bv_page; + bv->bv_offset = chunk->bv_offset; + } + bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset, + chunk->bv_len - iter->done); +} + /* * Get the last singlepage segment from the multipage bvec and store it * in @seg -- 2.9.5