linux/include/linux/bvec.h
<<
>>
Prefs
   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/mm.h>
  16#include <linux/types.h>
  17
  18struct page;
  19
  20/**
  21 * struct bio_vec - a contiguous range of physical memory addresses
  22 * @bv_page:   First page associated with the address range.
  23 * @bv_len:    Number of bytes in the address range.
  24 * @bv_offset: Start of the address range relative to the start of @bv_page.
  25 *
  26 * The following holds for a bvec if n * PAGE_SIZE < bv_offset + bv_len:
  27 *
  28 *   nth_page(@bv_page, n) == @bv_page + n
  29 *
  30 * This holds because page_is_mergeable() checks the above property.
  31 */
  32struct bio_vec {
  33        struct page     *bv_page;
  34        unsigned int    bv_len;
  35        unsigned int    bv_offset;
  36};
  37
  38struct bvec_iter {
  39        sector_t                bi_sector;      /* device address in 512 byte
  40                                                   sectors */
  41        unsigned int            bi_size;        /* residual I/O count */
  42
  43        unsigned int            bi_idx;         /* current index into bvl_vec */
  44
  45        unsigned int            bi_bvec_done;   /* number of bytes completed in
  46                                                   current bvec */
  47};
  48
  49struct bvec_iter_all {
  50        struct bio_vec  bv;
  51        int             idx;
  52        unsigned        done;
  53};
  54
  55/*
  56 * various member access, note that bio_data should of course not be used
  57 * on highmem page vectors
  58 */
  59#define __bvec_iter_bvec(bvec, iter)    (&(bvec)[(iter).bi_idx])
  60
  61/* multi-page (mp_bvec) helpers */
  62#define mp_bvec_iter_page(bvec, iter)                           \
  63        (__bvec_iter_bvec((bvec), (iter))->bv_page)
  64
  65#define mp_bvec_iter_len(bvec, iter)                            \
  66        min((iter).bi_size,                                     \
  67            __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done)
  68
  69#define mp_bvec_iter_offset(bvec, iter)                         \
  70        (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done)
  71
  72#define mp_bvec_iter_page_idx(bvec, iter)                       \
  73        (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE)
  74
  75#define mp_bvec_iter_bvec(bvec, iter)                           \
  76((struct bio_vec) {                                             \
  77        .bv_page        = mp_bvec_iter_page((bvec), (iter)),    \
  78        .bv_len         = mp_bvec_iter_len((bvec), (iter)),     \
  79        .bv_offset      = mp_bvec_iter_offset((bvec), (iter)),  \
  80})
  81
  82/* For building single-page bvec in flight */
  83 #define bvec_iter_offset(bvec, iter)                           \
  84        (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE)
  85
  86#define bvec_iter_len(bvec, iter)                               \
  87        min_t(unsigned, mp_bvec_iter_len((bvec), (iter)),               \
  88              PAGE_SIZE - bvec_iter_offset((bvec), (iter)))
  89
  90#define bvec_iter_page(bvec, iter)                              \
  91        (mp_bvec_iter_page((bvec), (iter)) +                    \
  92         mp_bvec_iter_page_idx((bvec), (iter)))
  93
  94#define bvec_iter_bvec(bvec, iter)                              \
  95((struct bio_vec) {                                             \
  96        .bv_page        = bvec_iter_page((bvec), (iter)),       \
  97        .bv_len         = bvec_iter_len((bvec), (iter)),        \
  98        .bv_offset      = bvec_iter_offset((bvec), (iter)),     \
  99})
 100
 101static inline bool bvec_iter_advance(const struct bio_vec *bv,
 102                struct bvec_iter *iter, unsigned bytes)
 103{
 104        unsigned int idx = iter->bi_idx;
 105
 106        if (WARN_ONCE(bytes > iter->bi_size,
 107                     "Attempted to advance past end of bvec iter\n")) {
 108                iter->bi_size = 0;
 109                return false;
 110        }
 111
 112        iter->bi_size -= bytes;
 113        bytes += iter->bi_bvec_done;
 114
 115        while (bytes && bytes >= bv[idx].bv_len) {
 116                bytes -= bv[idx].bv_len;
 117                idx++;
 118        }
 119
 120        iter->bi_idx = idx;
 121        iter->bi_bvec_done = bytes;
 122        return true;
 123}
 124
 125/*
 126 * A simpler version of bvec_iter_advance(), @bytes should not span
 127 * across multiple bvec entries, i.e. bytes <= bv[i->bi_idx].bv_len
 128 */
 129static inline void bvec_iter_advance_single(const struct bio_vec *bv,
 130                                struct bvec_iter *iter, unsigned int bytes)
 131{
 132        unsigned int done = iter->bi_bvec_done + bytes;
 133
 134        if (done == bv[iter->bi_idx].bv_len) {
 135                done = 0;
 136                iter->bi_idx++;
 137        }
 138        iter->bi_bvec_done = done;
 139        iter->bi_size -= bytes;
 140}
 141
 142#define for_each_bvec(bvl, bio_vec, iter, start)                        \
 143        for (iter = (start);                                            \
 144             (iter).bi_size &&                                          \
 145                ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \
 146             bvec_iter_advance_single((bio_vec), &(iter), (bvl).bv_len))
 147
 148/* for iterating one bio from start to end */
 149#define BVEC_ITER_ALL_INIT (struct bvec_iter)                           \
 150{                                                                       \
 151        .bi_sector      = 0,                                            \
 152        .bi_size        = UINT_MAX,                                     \
 153        .bi_idx         = 0,                                            \
 154        .bi_bvec_done   = 0,                                            \
 155}
 156
 157static inline struct bio_vec *bvec_init_iter_all(struct bvec_iter_all *iter_all)
 158{
 159        iter_all->done = 0;
 160        iter_all->idx = 0;
 161
 162        return &iter_all->bv;
 163}
 164
 165static inline void bvec_advance(const struct bio_vec *bvec,
 166                                struct bvec_iter_all *iter_all)
 167{
 168        struct bio_vec *bv = &iter_all->bv;
 169
 170        if (iter_all->done) {
 171                bv->bv_page++;
 172                bv->bv_offset = 0;
 173        } else {
 174                bv->bv_page = bvec->bv_page + (bvec->bv_offset >> PAGE_SHIFT);
 175                bv->bv_offset = bvec->bv_offset & ~PAGE_MASK;
 176        }
 177        bv->bv_len = min_t(unsigned int, PAGE_SIZE - bv->bv_offset,
 178                           bvec->bv_len - iter_all->done);
 179        iter_all->done += bv->bv_len;
 180
 181        if (iter_all->done == bvec->bv_len) {
 182                iter_all->idx++;
 183                iter_all->done = 0;
 184        }
 185}
 186
 187/**
 188 * bvec_kmap_local - map a bvec into the kernel virtual address space
 189 * @bvec: bvec to map
 190 *
 191 * Must be called on single-page bvecs only.  Call kunmap_local on the returned
 192 * address to unmap.
 193 */
 194static inline void *bvec_kmap_local(struct bio_vec *bvec)
 195{
 196        return kmap_local_page(bvec->bv_page) + bvec->bv_offset;
 197}
 198
 199/**
 200 * memcpy_from_bvec - copy data from a bvec
 201 * @bvec: bvec to copy from
 202 *
 203 * Must be called on single-page bvecs only.
 204 */
 205static inline void memcpy_from_bvec(char *to, struct bio_vec *bvec)
 206{
 207        memcpy_from_page(to, bvec->bv_page, bvec->bv_offset, bvec->bv_len);
 208}
 209
 210/**
 211 * memcpy_to_bvec - copy data to a bvec
 212 * @bvec: bvec to copy to
 213 *
 214 * Must be called on single-page bvecs only.
 215 */
 216static inline void memcpy_to_bvec(struct bio_vec *bvec, const char *from)
 217{
 218        memcpy_to_page(bvec->bv_page, bvec->bv_offset, from, bvec->bv_len);
 219}
 220
 221/**
 222 * memzero_bvec - zero all data in a bvec
 223 * @bvec: bvec to zero
 224 *
 225 * Must be called on single-page bvecs only.
 226 */
 227static inline void memzero_bvec(struct bio_vec *bvec)
 228{
 229        memzero_page(bvec->bv_page, bvec->bv_offset, bvec->bv_len);
 230}
 231
 232/**
 233 * bvec_virt - return the virtual address for a bvec
 234 * @bvec: bvec to return the virtual address for
 235 *
 236 * Note: the caller must ensure that @bvec->bv_page is not a highmem page.
 237 */
 238static inline void *bvec_virt(struct bio_vec *bvec)
 239{
 240        WARN_ON_ONCE(PageHighMem(bvec->bv_page));
 241        return page_address(bvec->bv_page) + bvec->bv_offset;
 242}
 243
 244#endif /* __LINUX_BVEC_H */
 245