1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /* I/O iterator iteration building functions.
4 * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
8 #ifndef _LINUX_IOV_ITER_H
9 #define _LINUX_IOV_ITER_H
11 #include <linux/uio.h>
12 #include <linux/bvec.h>
14 typedef size_t (*iov_step_f)(void *iter_base, size_t progress, size_t len,
15 void *priv, void *priv2);
16 typedef size_t (*iov_ustep_f)(void __user *iter_base, size_t progress, size_t len,
17 void *priv, void *priv2);
22 static __always_inline
23 size_t iterate_ubuf(struct iov_iter *iter, size_t len, void *priv, void *priv2,
26 void __user *base = iter->ubuf;
27 size_t progress = 0, remain;
29 remain = step(base + iter->iov_offset, 0, len, priv, priv2);
30 progress = len - remain;
31 iter->iov_offset += progress;
32 iter->count -= progress;
39 static __always_inline
40 size_t iterate_iovec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
43 const struct iovec *p = iter->__iov;
44 size_t progress = 0, skip = iter->iov_offset;
47 size_t remain, consumed;
48 size_t part = min(len, p->iov_len - skip);
51 remain = step(p->iov_base + skip, progress, part, priv, priv2);
52 consumed = part - remain;
56 if (skip < p->iov_len)
63 iter->nr_segs -= p - iter->__iov;
65 iter->iov_offset = skip;
66 iter->count -= progress;
73 static __always_inline
74 size_t iterate_kvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
77 const struct kvec *p = iter->kvec;
78 size_t progress = 0, skip = iter->iov_offset;
81 size_t remain, consumed;
82 size_t part = min(len, p->iov_len - skip);
85 remain = step(p->iov_base + skip, progress, part, priv, priv2);
86 consumed = part - remain;
90 if (skip < p->iov_len)
97 iter->nr_segs -= p - iter->kvec;
99 iter->iov_offset = skip;
100 iter->count -= progress;
107 static __always_inline
108 size_t iterate_bvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
111 const struct bio_vec *p = iter->bvec;
112 size_t progress = 0, skip = iter->iov_offset;
115 size_t remain, consumed;
116 size_t offset = p->bv_offset + skip, part;
117 void *kaddr = kmap_local_page(p->bv_page + offset / PAGE_SIZE);
120 (size_t)(p->bv_len - skip),
121 (size_t)(PAGE_SIZE - offset % PAGE_SIZE));
122 remain = step(kaddr + offset % PAGE_SIZE, progress, part, priv, priv2);
124 consumed = part - remain;
126 progress += consumed;
128 if (skip >= p->bv_len) {
136 iter->nr_segs -= p - iter->bvec;
138 iter->iov_offset = skip;
139 iter->count -= progress;
144 * Handle ITER_XARRAY.
146 static __always_inline
147 size_t iterate_xarray(struct iov_iter *iter, size_t len, void *priv, void *priv2,
152 loff_t start = iter->xarray_start + iter->iov_offset;
153 pgoff_t index = start / PAGE_SIZE;
154 XA_STATE(xas, iter->xarray, index);
157 xas_for_each(&xas, folio, ULONG_MAX) {
158 size_t remain, consumed, offset, part, flen;
160 if (xas_retry(&xas, folio))
162 if (WARN_ON(xa_is_value(folio)))
164 if (WARN_ON(folio_test_hugetlb(folio)))
167 offset = offset_in_folio(folio, start + progress);
168 flen = min(folio_size(folio) - offset, len);
171 void *base = kmap_local_folio(folio, offset);
173 part = min_t(size_t, flen,
174 PAGE_SIZE - offset_in_page(offset));
175 remain = step(base, progress, part, priv, priv2);
178 consumed = part - remain;
179 progress += consumed;
182 if (remain || len == 0)
191 iter->iov_offset += progress;
192 iter->count -= progress;
197 * Handle ITER_DISCARD.
199 static __always_inline
200 size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv2,
203 size_t progress = len;
205 iter->count -= progress;
210 * iterate_and_advance2 - Iterate over an iterator
211 * @iter: The iterator to iterate over.
212 * @len: The amount to iterate over.
213 * @priv: Data for the step functions.
214 * @priv2: More data for the step functions.
215 * @ustep: Function for UBUF/IOVEC iterators; given __user addresses.
216 * @step: Function for other iterators; given kernel addresses.
218 * Iterate over the next part of an iterator, up to the specified length. The
219 * buffer is presented in segments, which for kernel iteration are broken up by
220 * physical pages and mapped, with the mapped address being presented.
222 * Two step functions, @step and @ustep, must be provided, one for handling
223 * mapped kernel addresses and the other is given user addresses which have the
224 * potential to fault since no pinning is performed.
226 * The step functions are passed the address and length of the segment, @priv,
227 * @priv2 and the amount of data so far iterated over (which can, for example,
228 * be added to @priv to point to the right part of a second buffer). The step
229 * functions should return the amount of the segment they didn't process (ie. 0
230 * indicates complete processsing).
232 * This function returns the amount of data processed (ie. 0 means nothing was
233 * processed and the value of @len means processes to completion).
235 static __always_inline
236 size_t iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
237 void *priv2, iov_ustep_f ustep, iov_step_f step)
239 if (unlikely(iter->count < len))
244 if (likely(iter_is_ubuf(iter)))
245 return iterate_ubuf(iter, len, priv, priv2, ustep);
246 if (likely(iter_is_iovec(iter)))
247 return iterate_iovec(iter, len, priv, priv2, ustep);
248 if (iov_iter_is_bvec(iter))
249 return iterate_bvec(iter, len, priv, priv2, step);
250 if (iov_iter_is_kvec(iter))
251 return iterate_kvec(iter, len, priv, priv2, step);
252 if (iov_iter_is_xarray(iter))
253 return iterate_xarray(iter, len, priv, priv2, step);
254 return iterate_discard(iter, len, priv, priv2, step);
258 * iterate_and_advance - Iterate over an iterator
259 * @iter: The iterator to iterate over.
260 * @len: The amount to iterate over.
261 * @priv: Data for the step functions.
262 * @ustep: Function for UBUF/IOVEC iterators; given __user addresses.
263 * @step: Function for other iterators; given kernel addresses.
265 * As iterate_and_advance2(), but priv2 is always NULL.
267 static __always_inline
268 size_t iterate_and_advance(struct iov_iter *iter, size_t len, void *priv,
269 iov_ustep_f ustep, iov_step_f step)
271 return iterate_and_advance2(iter, len, priv, NULL, ustep, step);
274 #endif /* _LINUX_IOV_ITER_H */