aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2019-04-08 07:02:38 -0400
committerJens Axboe <axboe@kernel.dk>2019-04-08 10:19:41 -0400
commit1200e07f3ad4b9d976cf2fff3a0c3d9a1faecb3e (patch)
treec46db66fbb2979d69b7fe6ad6f9065ff9312e0a5
parent15ade5d2e7775667cf191cf2f94327a4889f8b9d (diff)
block: don't use for-inside-for in bio_for_each_segment_all
Commit 6dc4f100c175 ("block: allow bio_for_each_segment_all() to iterate over multi-page bvec") changes bio_for_each_segment_all() to use for-inside-for. This way breaks all bio_for_each_segment_all() call with error out branch via 'break', since now 'break' can only break from the inner loop. Fixes this issue by implementing bio_for_each_segment_all() via single 'for' loop, and now the logic is very similar with normal bvec iterator. Cc: Qu Wenruo <quwenruo.btrfs@gmx.com> Cc: linux-btrfs@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: Omar Sandoval <osandov@fb.com> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Reported-and-Tested-by: Qu Wenruo <quwenruo.btrfs@gmx.com> Fixes: 6dc4f100c175 ("block: allow bio_for_each_segment_all() to iterate over multi-page bvec") Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--include/linux/bio.h20
-rw-r--r--include/linux/bvec.h14
2 files changed, 22 insertions, 12 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h
index bb6090aa165d..e584673c1881 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -120,19 +120,23 @@ static inline bool bio_full(struct bio *bio)
120 return bio->bi_vcnt >= bio->bi_max_vecs; 120 return bio->bi_vcnt >= bio->bi_max_vecs;
121} 121}
122 122
123#define mp_bvec_for_each_segment(bv, bvl, i, iter_all) \ 123static inline bool bio_next_segment(const struct bio *bio,
124 for (bv = bvec_init_iter_all(&iter_all); \ 124 struct bvec_iter_all *iter)
125 (iter_all.done < (bvl)->bv_len) && \ 125{
126 (mp_bvec_next_segment((bvl), &iter_all), 1); \ 126 if (iter->idx >= bio->bi_vcnt)
127 iter_all.done += bv->bv_len, i += 1) 127 return false;
128
129 bvec_advance(&bio->bi_io_vec[iter->idx], iter);
130 return true;
131}
128 132
129/* 133/*
130 * drivers should _never_ use the all version - the bio may have been split 134 * drivers should _never_ use the all version - the bio may have been split
131 * before it got to the driver and the driver won't own all of it 135 * before it got to the driver and the driver won't own all of it
132 */ 136 */
133#define bio_for_each_segment_all(bvl, bio, i, iter_all) \ 137#define bio_for_each_segment_all(bvl, bio, i, iter) \
134 for (i = 0, iter_all.idx = 0; iter_all.idx < (bio)->bi_vcnt; iter_all.idx++) \ 138 for (i = 0, bvl = bvec_init_iter_all(&iter); \
135 mp_bvec_for_each_segment(bvl, &((bio)->bi_io_vec[iter_all.idx]), i, iter_all) 139 bio_next_segment((bio), &iter); i++)
136 140
137static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, 141static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter,
138 unsigned bytes) 142 unsigned bytes)
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index f6275c4da13a..3bc91879e1e2 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -145,18 +145,18 @@ static inline bool bvec_iter_advance(const struct bio_vec *bv,
145 145
146static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all) 146static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all)
147{ 147{
148 iter_all->bv.bv_page = NULL;
149 iter_all->done = 0; 148 iter_all->done = 0;
149 iter_all->idx = 0;
150 150
151 return &iter_all->bv; 151 return &iter_all->bv;
152} 152}
153 153
154static inline void mp_bvec_next_segment(const struct bio_vec *bvec, 154static inline void bvec_advance(const struct bio_vec *bvec,
155 struct bvec_iter_all *iter_all) 155 struct bvec_iter_all *iter_all)
156{ 156{
157 struct bio_vec *bv = &iter_all->bv; 157 struct bio_vec *bv = &iter_all->bv;
158 158
159 if (bv->bv_page) { 159 if (iter_all->done) {
160 bv->bv_page = nth_page(bv->bv_page, 1); 160 bv->bv_page = nth_page(bv->bv_page, 1);
161 bv->bv_offset = 0; 161 bv->bv_offset = 0;
162 } else { 162 } else {
@@ -165,6 +165,12 @@ static inline void mp_bvec_next_segment(const struct bio_vec *bvec,
165 } 165 }
166 bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset, 166 bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset,
167 bvec->bv_len - iter_all->done); 167 bvec->bv_len - iter_all->done);
168 iter_all->done += bv->bv_len;
169
170 if (iter_all->done == bvec->bv_len) {
171 iter_all->idx++;
172 iter_all->done = 0;
173 }
168} 174}
169 175
170/* 176/*