| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | /* | 
|---|
| 3 | * bvec iterator | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (C) 2001 Ming Lei <ming.lei@canonical.com> | 
|---|
| 6 | */ | 
|---|
| 7 | #ifndef __LINUX_BVEC_H | 
|---|
| 8 | #define __LINUX_BVEC_H | 
|---|
| 9 |  | 
|---|
| 10 | #include <linux/highmem.h> | 
|---|
| 11 | #include <linux/bug.h> | 
|---|
| 12 | #include <linux/errno.h> | 
|---|
| 13 | #include <linux/limits.h> | 
|---|
| 14 | #include <linux/minmax.h> | 
|---|
| 15 | #include <linux/types.h> | 
|---|
| 16 |  | 
|---|
| 17 | struct page; | 
|---|
| 18 |  | 
|---|
| 19 | /** | 
|---|
| 20 | * struct bio_vec - a contiguous range of physical memory addresses | 
|---|
| 21 | * @bv_page:   First page associated with the address range. | 
|---|
| 22 | * @bv_len:    Number of bytes in the address range. | 
|---|
| 23 | * @bv_offset: Start of the address range relative to the start of @bv_page. | 
|---|
| 24 | * | 
|---|
| 25 | * All pages within a bio_vec starting from @bv_page are contiguous and | 
|---|
| 26 | * can simply be iterated (see bvec_advance()). | 
|---|
| 27 | */ | 
|---|
| 28 | struct bio_vec { | 
|---|
| 29 | struct page	*bv_page; | 
|---|
| 30 | unsigned int	bv_len; | 
|---|
| 31 | unsigned int	bv_offset; | 
|---|
| 32 | }; | 
|---|
| 33 |  | 
|---|
| 34 | /** | 
|---|
| 35 | * bvec_set_page - initialize a bvec based off a struct page | 
|---|
| 36 | * @bv:		bvec to initialize | 
|---|
| 37 | * @page:	page the bvec should point to | 
|---|
| 38 | * @len:	length of the bvec | 
|---|
| 39 | * @offset:	offset into the page | 
|---|
| 40 | */ | 
|---|
| 41 | static inline void bvec_set_page(struct bio_vec *bv, struct page *page, | 
|---|
| 42 | unsigned int len, unsigned int offset) | 
|---|
| 43 | { | 
|---|
| 44 | bv->bv_page = page; | 
|---|
| 45 | bv->bv_len = len; | 
|---|
| 46 | bv->bv_offset = offset; | 
|---|
| 47 | } | 
|---|
| 48 |  | 
|---|
| 49 | /** | 
|---|
| 50 | * bvec_set_folio - initialize a bvec based off a struct folio | 
|---|
| 51 | * @bv:		bvec to initialize | 
|---|
| 52 | * @folio:	folio the bvec should point to | 
|---|
| 53 | * @len:	length of the bvec | 
|---|
| 54 | * @offset:	offset into the folio | 
|---|
| 55 | */ | 
|---|
| 56 | static inline void bvec_set_folio(struct bio_vec *bv, struct folio *folio, | 
|---|
| 57 | size_t len, size_t offset) | 
|---|
| 58 | { | 
|---|
| 59 | unsigned long nr = offset / PAGE_SIZE; | 
|---|
| 60 |  | 
|---|
| 61 | WARN_ON_ONCE(len > UINT_MAX); | 
|---|
| 62 | bvec_set_page(bv, folio_page(folio, nr), len, offset: offset % PAGE_SIZE); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | /** | 
|---|
| 66 | * bvec_set_virt - initialize a bvec based on a virtual address | 
|---|
| 67 | * @bv:		bvec to initialize | 
|---|
| 68 | * @vaddr:	virtual address to set the bvec to | 
|---|
| 69 | * @len:	length of the bvec | 
|---|
| 70 | */ | 
|---|
| 71 | static inline void bvec_set_virt(struct bio_vec *bv, void *vaddr, | 
|---|
| 72 | unsigned int len) | 
|---|
| 73 | { | 
|---|
| 74 | bvec_set_page(bv, virt_to_page(vaddr), len, offset_in_page(vaddr)); | 
|---|
| 75 | } | 
|---|
| 76 |  | 
|---|
| 77 | struct bvec_iter { | 
|---|
| 78 | sector_t		bi_sector;	/* device address in 512 byte | 
|---|
| 79 | sectors */ | 
|---|
| 80 | unsigned int		bi_size;	/* residual I/O count */ | 
|---|
| 81 |  | 
|---|
| 82 | unsigned int		bi_idx;		/* current index into bvl_vec */ | 
|---|
| 83 |  | 
|---|
| 84 | unsigned int            bi_bvec_done;	/* number of bytes completed in | 
|---|
| 85 | current bvec */ | 
|---|
| 86 | } __packed __aligned(4); | 
|---|
| 87 |  | 
|---|
| 88 | struct bvec_iter_all { | 
|---|
| 89 | struct bio_vec	bv; | 
|---|
| 90 | int		idx; | 
|---|
| 91 | unsigned	done; | 
|---|
| 92 | }; | 
|---|
| 93 |  | 
|---|
| 94 | /* | 
|---|
| 95 | * various member access, note that bio_data should of course not be used | 
|---|
| 96 | * on highmem page vectors | 
|---|
| 97 | */ | 
|---|
| 98 | #define __bvec_iter_bvec(bvec, iter)	(&(bvec)[(iter).bi_idx]) | 
|---|
| 99 |  | 
|---|
| 100 | /* multi-page (mp_bvec) helpers */ | 
|---|
| 101 | #define mp_bvec_iter_page(bvec, iter)				\ | 
|---|
| 102 | (__bvec_iter_bvec((bvec), (iter))->bv_page) | 
|---|
| 103 |  | 
|---|
| 104 | #define mp_bvec_iter_len(bvec, iter)				\ | 
|---|
| 105 | min((iter).bi_size,					\ | 
|---|
| 106 | __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) | 
|---|
| 107 |  | 
|---|
| 108 | #define mp_bvec_iter_offset(bvec, iter)				\ | 
|---|
| 109 | (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) | 
|---|
| 110 |  | 
|---|
| 111 | #define mp_bvec_iter_page_idx(bvec, iter)			\ | 
|---|
| 112 | (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE) | 
|---|
| 113 |  | 
|---|
| 114 | #define mp_bvec_iter_bvec(bvec, iter)				\ | 
|---|
| 115 | ((struct bio_vec) {						\ | 
|---|
| 116 | .bv_page	= mp_bvec_iter_page((bvec), (iter)),	\ | 
|---|
| 117 | .bv_len		= mp_bvec_iter_len((bvec), (iter)),	\ | 
|---|
| 118 | .bv_offset	= mp_bvec_iter_offset((bvec), (iter)),	\ | 
|---|
| 119 | }) | 
|---|
| 120 |  | 
|---|
| 121 | /* For building single-page bvec in flight */ | 
|---|
| 122 | #define bvec_iter_offset(bvec, iter)				\ | 
|---|
| 123 | (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE) | 
|---|
| 124 |  | 
|---|
| 125 | #define bvec_iter_len(bvec, iter)				\ | 
|---|
| 126 | min_t(unsigned, mp_bvec_iter_len((bvec), (iter)),		\ | 
|---|
| 127 | PAGE_SIZE - bvec_iter_offset((bvec), (iter))) | 
|---|
| 128 |  | 
|---|
| 129 | #define bvec_iter_page(bvec, iter)				\ | 
|---|
| 130 | (mp_bvec_iter_page((bvec), (iter)) +			\ | 
|---|
| 131 | mp_bvec_iter_page_idx((bvec), (iter))) | 
|---|
| 132 |  | 
|---|
| 133 | #define bvec_iter_bvec(bvec, iter)				\ | 
|---|
| 134 | ((struct bio_vec) {						\ | 
|---|
| 135 | .bv_page	= bvec_iter_page((bvec), (iter)),	\ | 
|---|
| 136 | .bv_len		= bvec_iter_len((bvec), (iter)),	\ | 
|---|
| 137 | .bv_offset	= bvec_iter_offset((bvec), (iter)),	\ | 
|---|
| 138 | }) | 
|---|
| 139 |  | 
|---|
| 140 | static inline bool bvec_iter_advance(const struct bio_vec *bv, | 
|---|
| 141 | struct bvec_iter *iter, unsigned bytes) | 
|---|
| 142 | { | 
|---|
| 143 | unsigned int idx = iter->bi_idx; | 
|---|
| 144 |  | 
|---|
| 145 | if (WARN_ONCE(bytes > iter->bi_size, | 
|---|
| 146 | "Attempted to advance past end of bvec iter\n")) { | 
|---|
| 147 | iter->bi_size = 0; | 
|---|
| 148 | return false; | 
|---|
| 149 | } | 
|---|
| 150 |  | 
|---|
| 151 | iter->bi_size -= bytes; | 
|---|
| 152 | bytes += iter->bi_bvec_done; | 
|---|
| 153 |  | 
|---|
| 154 | while (bytes && bytes >= bv[idx].bv_len) { | 
|---|
| 155 | bytes -= bv[idx].bv_len; | 
|---|
| 156 | idx++; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | iter->bi_idx = idx; | 
|---|
| 160 | iter->bi_bvec_done = bytes; | 
|---|
| 161 | return true; | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | /* | 
|---|
| 165 | * A simpler version of bvec_iter_advance(), @bytes should not span | 
|---|
| 166 | * across multiple bvec entries, i.e. bytes <= bv[i->bi_idx].bv_len | 
|---|
| 167 | */ | 
|---|
| 168 | static inline void bvec_iter_advance_single(const struct bio_vec *bv, | 
|---|
| 169 | struct bvec_iter *iter, unsigned int bytes) | 
|---|
| 170 | { | 
|---|
| 171 | unsigned int done = iter->bi_bvec_done + bytes; | 
|---|
| 172 |  | 
|---|
| 173 | if (done == bv[iter->bi_idx].bv_len) { | 
|---|
| 174 | done = 0; | 
|---|
| 175 | iter->bi_idx++; | 
|---|
| 176 | } | 
|---|
| 177 | iter->bi_bvec_done = done; | 
|---|
| 178 | iter->bi_size -= bytes; | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | #define for_each_bvec(bvl, bio_vec, iter, start)			\ | 
|---|
| 182 | for (iter = (start);						\ | 
|---|
| 183 | (iter).bi_size &&						\ | 
|---|
| 184 | ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1);	\ | 
|---|
| 185 | bvec_iter_advance_single((bio_vec), &(iter), (bvl).bv_len)) | 
|---|
| 186 |  | 
|---|
| 187 | #define for_each_mp_bvec(bvl, bio_vec, iter, start)			\ | 
|---|
| 188 | for (iter = (start);						\ | 
|---|
| 189 | (iter).bi_size &&						\ | 
|---|
| 190 | ((bvl = mp_bvec_iter_bvec((bio_vec), (iter))), 1);	\ | 
|---|
| 191 | bvec_iter_advance_single((bio_vec), &(iter), (bvl).bv_len)) | 
|---|
| 192 |  | 
|---|
| 193 | /* for iterating one bio from start to end */ | 
|---|
| 194 | #define BVEC_ITER_ALL_INIT (struct bvec_iter)				\ | 
|---|
| 195 | {									\ | 
|---|
| 196 | .bi_sector	= 0,						\ | 
|---|
| 197 | .bi_size	= UINT_MAX,					\ | 
|---|
| 198 | .bi_idx		= 0,						\ | 
|---|
| 199 | .bi_bvec_done	= 0,						\ | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all) | 
|---|
| 203 | { | 
|---|
| 204 | iter_all->done = 0; | 
|---|
| 205 | iter_all->idx = 0; | 
|---|
| 206 |  | 
|---|
| 207 | return &iter_all->bv; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | static inline void bvec_advance(const struct bio_vec *bvec, | 
|---|
| 211 | struct bvec_iter_all *iter_all) | 
|---|
| 212 | { | 
|---|
| 213 | struct bio_vec *bv = &iter_all->bv; | 
|---|
| 214 |  | 
|---|
| 215 | if (iter_all->done) { | 
|---|
| 216 | bv->bv_page++; | 
|---|
| 217 | bv->bv_offset = 0; | 
|---|
| 218 | } else { | 
|---|
| 219 | bv->bv_page = bvec->bv_page + (bvec->bv_offset >> PAGE_SHIFT); | 
|---|
| 220 | bv->bv_offset = bvec->bv_offset & ~PAGE_MASK; | 
|---|
| 221 | } | 
|---|
| 222 | bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset, | 
|---|
| 223 | bvec->bv_len - iter_all->done); | 
|---|
| 224 | iter_all->done += bv->bv_len; | 
|---|
| 225 |  | 
|---|
| 226 | if (iter_all->done == bvec->bv_len) { | 
|---|
| 227 | iter_all->idx++; | 
|---|
| 228 | iter_all->done = 0; | 
|---|
| 229 | } | 
|---|
| 230 | } | 
|---|
| 231 |  | 
|---|
| 232 | /** | 
|---|
| 233 | * bvec_kmap_local - map a bvec into the kernel virtual address space | 
|---|
| 234 | * @bvec: bvec to map | 
|---|
| 235 | * | 
|---|
| 236 | * Must be called on single-page bvecs only.  Call kunmap_local on the returned | 
|---|
| 237 | * address to unmap. | 
|---|
| 238 | */ | 
|---|
| 239 | static inline void *bvec_kmap_local(struct bio_vec *bvec) | 
|---|
| 240 | { | 
|---|
| 241 | return kmap_local_page(page: bvec->bv_page) + bvec->bv_offset; | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 | /** | 
|---|
| 245 | * memcpy_from_bvec - copy data from a bvec | 
|---|
| 246 | * @bvec: bvec to copy from | 
|---|
| 247 | * | 
|---|
| 248 | * Must be called on single-page bvecs only. | 
|---|
| 249 | */ | 
|---|
| 250 | static inline void memcpy_from_bvec(char *to, struct bio_vec *bvec) | 
|---|
| 251 | { | 
|---|
| 252 | memcpy_from_page(to, page: bvec->bv_page, offset: bvec->bv_offset, len: bvec->bv_len); | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | /** | 
|---|
| 256 | * memcpy_to_bvec - copy data to a bvec | 
|---|
| 257 | * @bvec: bvec to copy to | 
|---|
| 258 | * | 
|---|
| 259 | * Must be called on single-page bvecs only. | 
|---|
| 260 | */ | 
|---|
| 261 | static inline void memcpy_to_bvec(struct bio_vec *bvec, const char *from) | 
|---|
| 262 | { | 
|---|
| 263 | memcpy_to_page(page: bvec->bv_page, offset: bvec->bv_offset, from, len: bvec->bv_len); | 
|---|
| 264 | } | 
|---|
| 265 |  | 
|---|
| 266 | /** | 
|---|
| 267 | * memzero_bvec - zero all data in a bvec | 
|---|
| 268 | * @bvec: bvec to zero | 
|---|
| 269 | * | 
|---|
| 270 | * Must be called on single-page bvecs only. | 
|---|
| 271 | */ | 
|---|
| 272 | static inline void memzero_bvec(struct bio_vec *bvec) | 
|---|
| 273 | { | 
|---|
| 274 | memzero_page(page: bvec->bv_page, offset: bvec->bv_offset, len: bvec->bv_len); | 
|---|
| 275 | } | 
|---|
| 276 |  | 
|---|
| 277 | /** | 
|---|
| 278 | * bvec_virt - return the virtual address for a bvec | 
|---|
| 279 | * @bvec: bvec to return the virtual address for | 
|---|
| 280 | * | 
|---|
| 281 | * Note: the caller must ensure that @bvec->bv_page is not a highmem page. | 
|---|
| 282 | */ | 
|---|
| 283 | static inline void *bvec_virt(struct bio_vec *bvec) | 
|---|
| 284 | { | 
|---|
| 285 | WARN_ON_ONCE(PageHighMem(bvec->bv_page)); | 
|---|
| 286 | return page_address(bvec->bv_page) + bvec->bv_offset; | 
|---|
| 287 | } | 
|---|
| 288 |  | 
|---|
| 289 | /** | 
|---|
| 290 | * bvec_phys - return the physical address for a bvec | 
|---|
| 291 | * @bvec: bvec to return the physical address for | 
|---|
| 292 | */ | 
|---|
| 293 | static inline phys_addr_t bvec_phys(const struct bio_vec *bvec) | 
|---|
| 294 | { | 
|---|
| 295 | return page_to_phys(bvec->bv_page) + bvec->bv_offset; | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | #endif /* __LINUX_BVEC_H */ | 
|---|
| 299 |  | 
|---|