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 /* 55 * various member access, note that bio_data should of course not be used 56 * on highmem page vectors 57 */ 58 #define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) 59 60 /* multi-page (mp_bvec) helpers */ 61 #define mp_bvec_iter_page(bvec, iter) \ 62 (__bvec_iter_bvec((bvec), (iter))->bv_page) 63 64 #define mp_bvec_iter_len(bvec, iter) \ 65 min((iter).bi_size, \ 66 __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) 67 68 #define mp_bvec_iter_offset(bvec, iter) \ 69 (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) 70 71 #define mp_bvec_iter_page_idx(bvec, iter) \ 72 (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE) 73 74 #define mp_bvec_iter_bvec(bvec, iter) \ 75 ((struct bio_vec) { \ 76 .bv_page = mp_bvec_iter_page((bvec), (iter)), \ 77 .bv_len = mp_bvec_iter_len((bvec), (iter)), \ 78 .bv_offset = mp_bvec_iter_offset((bvec), (iter)), \ 79 }) 80 81 /* For building single-page bvec in flight */ 82 #define bvec_iter_offset(bvec, iter) \ 83 (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE) 84 85 #define bvec_iter_len(bvec, iter) \ 86 min_t(unsigned, mp_bvec_iter_len((bvec), (iter)), \ 87 PAGE_SIZE - bvec_iter_offset((bvec), (iter))) 88 89 #define bvec_iter_page(bvec, iter) \ 90 (mp_bvec_iter_page((bvec), (iter)) + \ 91 mp_bvec_iter_page_idx((bvec), (iter))) 92 93 #define bvec_iter_bvec(bvec, iter) \ 94 ((struct bio_vec) { \ 95 .bv_page = bvec_iter_page((bvec), (iter)), \ 96 .bv_len = bvec_iter_len((bvec), (iter)), \ 97 .bv_offset = bvec_iter_offset((bvec), (iter)), \ 98 }) 99 100 static inline bool bvec_iter_advance(const struct bio_vec *bv, 101 struct bvec_iter *iter, unsigned bytes) 102 { 103 if (WARN_ONCE(bytes > iter->bi_size, 104 "Attempted to advance past end of bvec iter\n")) { 105 iter->bi_size = 0; 106 return false; 107 } 108 109 while (bytes) { 110 const struct bio_vec *cur = bv + iter->bi_idx; 111 unsigned len = min3(bytes, iter->bi_size, 112 cur->bv_len - iter->bi_bvec_done); 113 114 bytes -= len; 115 iter->bi_size -= len; 116 iter->bi_bvec_done += len; 117 118 if (iter->bi_bvec_done == cur->bv_len) { 119 iter->bi_bvec_done = 0; 120 iter->bi_idx++; 121 } 122 } 123 return true; 124 } 125 126 #define for_each_bvec(bvl, bio_vec, iter, start) \ 127 for (iter = (start); \ 128 (iter).bi_size && \ 129 ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \ 130 bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) 131 132 /* for iterating one bio from start to end */ 133 #define BVEC_ITER_ALL_INIT (struct bvec_iter) \ 134 { \ 135 .bi_sector = 0, \ 136 .bi_size = UINT_MAX, \ 137 .bi_idx = 0, \ 138 .bi_bvec_done = 0, \ 139 } 140 141 static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all) 142 { 143 iter_all->bv.bv_page = NULL; 144 iter_all->done = 0; 145 146 return &iter_all->bv; 147 } 148 149 static inline void mp_bvec_next_segment(const struct bio_vec *bvec, 150 struct bvec_iter_all *iter_all) 151 { 152 struct bio_vec *bv = &iter_all->bv; 153 154 if (bv->bv_page) { 155 bv->bv_page++; 156 bv->bv_offset = 0; 157 } else { 158 bv->bv_page = bvec->bv_page; 159 bv->bv_offset = bvec->bv_offset; 160 } 161 bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset, 162 bvec->bv_len - iter_all->done); 163 } 164 165 /* 166 * Get the last single-page segment from the multi-page bvec and store it 167 * in @seg 168 */ 169 static inline void mp_bvec_last_segment(const struct bio_vec *bvec, 170 struct bio_vec *seg) 171 { 172 unsigned total = bvec->bv_offset + bvec->bv_len; 173 unsigned last_page = (total - 1) / PAGE_SIZE; 174 175 seg->bv_page = bvec->bv_page + last_page; 176 177 /* the whole segment is inside the last page */ 178 if (bvec->bv_offset >= last_page * PAGE_SIZE) { 179 seg->bv_offset = bvec->bv_offset % PAGE_SIZE; 180 seg->bv_len = bvec->bv_len; 181 } else { 182 seg->bv_offset = 0; 183 seg->bv_len = total - last_page * PAGE_SIZE; 184 } 185 } 186 187 #endif /* __LINUX_BVEC_ITER_H */ 188