1 /* 2 * bvec iterator 3 * 4 * Copyright (C) 2001 Ming Lei <ming.lei@canonical.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public Licens 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- 19 */ 20 #ifndef __LINUX_BVEC_ITER_H 21 #define __LINUX_BVEC_ITER_H 22 23 #include <linux/kernel.h> 24 #include <linux/bug.h> 25 #include <linux/errno.h> 26 #include <linux/mm.h> 27 28 /* 29 * was unsigned short, but we might as well be ready for > 64kB I/O pages 30 */ 31 struct bio_vec { 32 struct page *bv_page; 33 unsigned int bv_len; 34 unsigned int bv_offset; 35 }; 36 37 struct bvec_iter { 38 sector_t bi_sector; /* device address in 512 byte 39 sectors */ 40 unsigned int bi_size; /* residual I/O count */ 41 42 unsigned int bi_idx; /* current index into bvl_vec */ 43 44 unsigned int bi_bvec_done; /* number of bytes completed in 45 current bvec */ 46 }; 47 48 struct bvec_iter_all { 49 struct bio_vec bv; 50 int idx; 51 unsigned done; 52 }; 53 54 static inline struct page *bvec_nth_page(struct page *page, int idx) 55 { 56 return idx == 0 ? page : nth_page(page, idx); 57 } 58 59 /* 60 * various member access, note that bio_data should of course not be used 61 * on highmem page vectors 62 */ 63 #define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) 64 65 /* multi-page (mp_bvec) helpers */ 66 #define mp_bvec_iter_page(bvec, iter) \ 67 (__bvec_iter_bvec((bvec), (iter))->bv_page) 68 69 #define mp_bvec_iter_len(bvec, iter) \ 70 min((iter).bi_size, \ 71 __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) 72 73 #define mp_bvec_iter_offset(bvec, iter) \ 74 (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) 75 76 #define mp_bvec_iter_page_idx(bvec, iter) \ 77 (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE) 78 79 #define mp_bvec_iter_bvec(bvec, iter) \ 80 ((struct bio_vec) { \ 81 .bv_page = mp_bvec_iter_page((bvec), (iter)), \ 82 .bv_len = mp_bvec_iter_len((bvec), (iter)), \ 83 .bv_offset = mp_bvec_iter_offset((bvec), (iter)), \ 84 }) 85 86 /* For building single-page bvec in flight */ 87 #define bvec_iter_offset(bvec, iter) \ 88 (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE) 89 90 #define bvec_iter_len(bvec, iter) \ 91 min_t(unsigned, mp_bvec_iter_len((bvec), (iter)), \ 92 PAGE_SIZE - bvec_iter_offset((bvec), (iter))) 93 94 #define bvec_iter_page(bvec, iter) \ 95 bvec_nth_page(mp_bvec_iter_page((bvec), (iter)), \ 96 mp_bvec_iter_page_idx((bvec), (iter))) 97 98 #define bvec_iter_bvec(bvec, iter) \ 99 ((struct bio_vec) { \ 100 .bv_page = bvec_iter_page((bvec), (iter)), \ 101 .bv_len = bvec_iter_len((bvec), (iter)), \ 102 .bv_offset = bvec_iter_offset((bvec), (iter)), \ 103 }) 104 105 static inline bool bvec_iter_advance(const struct bio_vec *bv, 106 struct bvec_iter *iter, unsigned bytes) 107 { 108 if (WARN_ONCE(bytes > iter->bi_size, 109 "Attempted to advance past end of bvec iter\n")) { 110 iter->bi_size = 0; 111 return false; 112 } 113 114 while (bytes) { 115 const struct bio_vec *cur = bv + iter->bi_idx; 116 unsigned len = min3(bytes, iter->bi_size, 117 cur->bv_len - iter->bi_bvec_done); 118 119 bytes -= len; 120 iter->bi_size -= len; 121 iter->bi_bvec_done += len; 122 123 if (iter->bi_bvec_done == cur->bv_len) { 124 iter->bi_bvec_done = 0; 125 iter->bi_idx++; 126 } 127 } 128 return true; 129 } 130 131 #define for_each_bvec(bvl, bio_vec, iter, start) \ 132 for (iter = (start); \ 133 (iter).bi_size && \ 134 ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \ 135 bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) 136 137 /* for iterating one bio from start to end */ 138 #define BVEC_ITER_ALL_INIT (struct bvec_iter) \ 139 { \ 140 .bi_sector = 0, \ 141 .bi_size = UINT_MAX, \ 142 .bi_idx = 0, \ 143 .bi_bvec_done = 0, \ 144 } 145 146 static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all) 147 { 148 iter_all->bv.bv_page = NULL; 149 iter_all->done = 0; 150 151 return &iter_all->bv; 152 } 153 154 static inline void mp_bvec_next_segment(const struct bio_vec *bvec, 155 struct bvec_iter_all *iter_all) 156 { 157 struct bio_vec *bv = &iter_all->bv; 158 159 if (bv->bv_page) { 160 bv->bv_page = nth_page(bv->bv_page, 1); 161 bv->bv_offset = 0; 162 } else { 163 bv->bv_page = bvec->bv_page; 164 bv->bv_offset = bvec->bv_offset; 165 } 166 bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset, 167 bvec->bv_len - iter_all->done); 168 } 169 170 /* 171 * Get the last single-page segment from the multi-page bvec and store it 172 * in @seg 173 */ 174 static inline void mp_bvec_last_segment(const struct bio_vec *bvec, 175 struct bio_vec *seg) 176 { 177 unsigned total = bvec->bv_offset + bvec->bv_len; 178 unsigned last_page = (total - 1) / PAGE_SIZE; 179 180 seg->bv_page = bvec_nth_page(bvec->bv_page, last_page); 181 182 /* the whole segment is inside the last page */ 183 if (bvec->bv_offset >= last_page * PAGE_SIZE) { 184 seg->bv_offset = bvec->bv_offset % PAGE_SIZE; 185 seg->bv_len = bvec->bv_len; 186 } else { 187 seg->bv_offset = 0; 188 seg->bv_len = total - last_page * PAGE_SIZE; 189 } 190 } 191 192 #define mp_bvec_for_each_page(pg, bv, i) \ 193 for (i = (bv)->bv_offset / PAGE_SIZE; \ 194 (i <= (((bv)->bv_offset + (bv)->bv_len - 1) / PAGE_SIZE)) && \ 195 (pg = bvec_nth_page((bv)->bv_page, i)); i += 1) 196 197 #endif /* __LINUX_BVEC_ITER_H */ 198