xref: /linux-6.15/include/linux/iov_iter.h (revision 2982c8c1)
1f1982740SDavid Howells /* SPDX-License-Identifier: GPL-2.0-or-later */
2f1982740SDavid Howells /* I/O iterator iteration building functions.
3f1982740SDavid Howells  *
4f1982740SDavid Howells  * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
5f1982740SDavid Howells  * Written by David Howells ([email protected])
6f1982740SDavid Howells  */
7f1982740SDavid Howells 
8f1982740SDavid Howells #ifndef _LINUX_IOV_ITER_H
9f1982740SDavid Howells #define _LINUX_IOV_ITER_H
10f1982740SDavid Howells 
11f1982740SDavid Howells #include <linux/uio.h>
12f1982740SDavid Howells #include <linux/bvec.h>
13db0aa2e9SDavid Howells #include <linux/folio_queue.h>
14f1982740SDavid Howells 
15f1982740SDavid Howells typedef size_t (*iov_step_f)(void *iter_base, size_t progress, size_t len,
16f1982740SDavid Howells 			     void *priv, void *priv2);
17f1982740SDavid Howells typedef size_t (*iov_ustep_f)(void __user *iter_base, size_t progress, size_t len,
18f1982740SDavid Howells 			      void *priv, void *priv2);
19f1982740SDavid Howells 
20f1982740SDavid Howells /*
21f1982740SDavid Howells  * Handle ITER_UBUF.
22f1982740SDavid Howells  */
23f1982740SDavid Howells static __always_inline
iterate_ubuf(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_ustep_f step)24f1982740SDavid Howells size_t iterate_ubuf(struct iov_iter *iter, size_t len, void *priv, void *priv2,
25f1982740SDavid Howells 		    iov_ustep_f step)
26f1982740SDavid Howells {
27f1982740SDavid Howells 	void __user *base = iter->ubuf;
28f1982740SDavid Howells 	size_t progress = 0, remain;
29f1982740SDavid Howells 
30f1982740SDavid Howells 	remain = step(base + iter->iov_offset, 0, len, priv, priv2);
31f1982740SDavid Howells 	progress = len - remain;
32f1982740SDavid Howells 	iter->iov_offset += progress;
33f1982740SDavid Howells 	iter->count -= progress;
34f1982740SDavid Howells 	return progress;
35f1982740SDavid Howells }
36f1982740SDavid Howells 
37f1982740SDavid Howells /*
38f1982740SDavid Howells  * Handle ITER_IOVEC.
39f1982740SDavid Howells  */
40f1982740SDavid Howells static __always_inline
iterate_iovec(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_ustep_f step)41f1982740SDavid Howells size_t iterate_iovec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
42f1982740SDavid Howells 		     iov_ustep_f step)
43f1982740SDavid Howells {
44f1982740SDavid Howells 	const struct iovec *p = iter->__iov;
45f1982740SDavid Howells 	size_t progress = 0, skip = iter->iov_offset;
46f1982740SDavid Howells 
47f1982740SDavid Howells 	do {
48f1982740SDavid Howells 		size_t remain, consumed;
49f1982740SDavid Howells 		size_t part = min(len, p->iov_len - skip);
50f1982740SDavid Howells 
51f1982740SDavid Howells 		if (likely(part)) {
52f1982740SDavid Howells 			remain = step(p->iov_base + skip, progress, part, priv, priv2);
53f1982740SDavid Howells 			consumed = part - remain;
54f1982740SDavid Howells 			progress += consumed;
55f1982740SDavid Howells 			skip += consumed;
56f1982740SDavid Howells 			len -= consumed;
57f1982740SDavid Howells 			if (skip < p->iov_len)
58f1982740SDavid Howells 				break;
59f1982740SDavid Howells 		}
60f1982740SDavid Howells 		p++;
61f1982740SDavid Howells 		skip = 0;
62f1982740SDavid Howells 	} while (len);
63f1982740SDavid Howells 
64f1982740SDavid Howells 	iter->nr_segs -= p - iter->__iov;
65f1982740SDavid Howells 	iter->__iov = p;
66f1982740SDavid Howells 	iter->iov_offset = skip;
67f1982740SDavid Howells 	iter->count -= progress;
68f1982740SDavid Howells 	return progress;
69f1982740SDavid Howells }
70f1982740SDavid Howells 
71f1982740SDavid Howells /*
72f1982740SDavid Howells  * Handle ITER_KVEC.
73f1982740SDavid Howells  */
74f1982740SDavid Howells static __always_inline
iterate_kvec(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)75f1982740SDavid Howells size_t iterate_kvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
76f1982740SDavid Howells 		    iov_step_f step)
77f1982740SDavid Howells {
78f1982740SDavid Howells 	const struct kvec *p = iter->kvec;
79f1982740SDavid Howells 	size_t progress = 0, skip = iter->iov_offset;
80f1982740SDavid Howells 
81f1982740SDavid Howells 	do {
82f1982740SDavid Howells 		size_t remain, consumed;
83f1982740SDavid Howells 		size_t part = min(len, p->iov_len - skip);
84f1982740SDavid Howells 
85f1982740SDavid Howells 		if (likely(part)) {
86f1982740SDavid Howells 			remain = step(p->iov_base + skip, progress, part, priv, priv2);
87f1982740SDavid Howells 			consumed = part - remain;
88f1982740SDavid Howells 			progress += consumed;
89f1982740SDavid Howells 			skip += consumed;
90f1982740SDavid Howells 			len -= consumed;
91f1982740SDavid Howells 			if (skip < p->iov_len)
92f1982740SDavid Howells 				break;
93f1982740SDavid Howells 		}
94f1982740SDavid Howells 		p++;
95f1982740SDavid Howells 		skip = 0;
96f1982740SDavid Howells 	} while (len);
97f1982740SDavid Howells 
98f1982740SDavid Howells 	iter->nr_segs -= p - iter->kvec;
99f1982740SDavid Howells 	iter->kvec = p;
100f1982740SDavid Howells 	iter->iov_offset = skip;
101f1982740SDavid Howells 	iter->count -= progress;
102f1982740SDavid Howells 	return progress;
103f1982740SDavid Howells }
104f1982740SDavid Howells 
105f1982740SDavid Howells /*
106f1982740SDavid Howells  * Handle ITER_BVEC.
107f1982740SDavid Howells  */
108f1982740SDavid Howells static __always_inline
iterate_bvec(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)109f1982740SDavid Howells size_t iterate_bvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
110f1982740SDavid Howells 		    iov_step_f step)
111f1982740SDavid Howells {
112f1982740SDavid Howells 	const struct bio_vec *p = iter->bvec;
113f1982740SDavid Howells 	size_t progress = 0, skip = iter->iov_offset;
114f1982740SDavid Howells 
115f1982740SDavid Howells 	do {
116f1982740SDavid Howells 		size_t remain, consumed;
117f1982740SDavid Howells 		size_t offset = p->bv_offset + skip, part;
118f1982740SDavid Howells 		void *kaddr = kmap_local_page(p->bv_page + offset / PAGE_SIZE);
119f1982740SDavid Howells 
120f1982740SDavid Howells 		part = min3(len,
121f1982740SDavid Howells 			   (size_t)(p->bv_len - skip),
122f1982740SDavid Howells 			   (size_t)(PAGE_SIZE - offset % PAGE_SIZE));
123f1982740SDavid Howells 		remain = step(kaddr + offset % PAGE_SIZE, progress, part, priv, priv2);
124f1982740SDavid Howells 		kunmap_local(kaddr);
125f1982740SDavid Howells 		consumed = part - remain;
126f1982740SDavid Howells 		len -= consumed;
127f1982740SDavid Howells 		progress += consumed;
128f1982740SDavid Howells 		skip += consumed;
129f1982740SDavid Howells 		if (skip >= p->bv_len) {
130f1982740SDavid Howells 			skip = 0;
131f1982740SDavid Howells 			p++;
132f1982740SDavid Howells 		}
133f1982740SDavid Howells 		if (remain)
134f1982740SDavid Howells 			break;
135f1982740SDavid Howells 	} while (len);
136f1982740SDavid Howells 
137f1982740SDavid Howells 	iter->nr_segs -= p - iter->bvec;
138f1982740SDavid Howells 	iter->bvec = p;
139f1982740SDavid Howells 	iter->iov_offset = skip;
140f1982740SDavid Howells 	iter->count -= progress;
141f1982740SDavid Howells 	return progress;
142f1982740SDavid Howells }
143f1982740SDavid Howells 
144f1982740SDavid Howells /*
145db0aa2e9SDavid Howells  * Handle ITER_FOLIOQ.
146db0aa2e9SDavid Howells  */
147db0aa2e9SDavid Howells static __always_inline
iterate_folioq(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)148db0aa2e9SDavid Howells size_t iterate_folioq(struct iov_iter *iter, size_t len, void *priv, void *priv2,
149db0aa2e9SDavid Howells 		      iov_step_f step)
150db0aa2e9SDavid Howells {
151db0aa2e9SDavid Howells 	const struct folio_queue *folioq = iter->folioq;
152db0aa2e9SDavid Howells 	unsigned int slot = iter->folioq_slot;
153db0aa2e9SDavid Howells 	size_t progress = 0, skip = iter->iov_offset;
154db0aa2e9SDavid Howells 
155db0aa2e9SDavid Howells 	if (slot == folioq_nr_slots(folioq)) {
156db0aa2e9SDavid Howells 		/* The iterator may have been extended. */
157db0aa2e9SDavid Howells 		folioq = folioq->next;
158db0aa2e9SDavid Howells 		slot = 0;
159db0aa2e9SDavid Howells 	}
160db0aa2e9SDavid Howells 
161db0aa2e9SDavid Howells 	do {
162db0aa2e9SDavid Howells 		struct folio *folio = folioq_folio(folioq, slot);
163db0aa2e9SDavid Howells 		size_t part, remain, consumed;
164db0aa2e9SDavid Howells 		size_t fsize;
165db0aa2e9SDavid Howells 		void *base;
166db0aa2e9SDavid Howells 
167db0aa2e9SDavid Howells 		if (!folio)
168db0aa2e9SDavid Howells 			break;
169db0aa2e9SDavid Howells 
170db0aa2e9SDavid Howells 		fsize = folioq_folio_size(folioq, slot);
171db0aa2e9SDavid Howells 		base = kmap_local_folio(folio, skip);
172db0aa2e9SDavid Howells 		part = umin(len, PAGE_SIZE - skip % PAGE_SIZE);
173db0aa2e9SDavid Howells 		remain = step(base, progress, part, priv, priv2);
174db0aa2e9SDavid Howells 		kunmap_local(base);
175db0aa2e9SDavid Howells 		consumed = part - remain;
176db0aa2e9SDavid Howells 		len -= consumed;
177db0aa2e9SDavid Howells 		progress += consumed;
178db0aa2e9SDavid Howells 		skip += consumed;
179db0aa2e9SDavid Howells 		if (skip >= fsize) {
180db0aa2e9SDavid Howells 			skip = 0;
181db0aa2e9SDavid Howells 			slot++;
182db0aa2e9SDavid Howells 			if (slot == folioq_nr_slots(folioq) && folioq->next) {
183db0aa2e9SDavid Howells 				folioq = folioq->next;
184db0aa2e9SDavid Howells 				slot = 0;
185db0aa2e9SDavid Howells 			}
186db0aa2e9SDavid Howells 		}
187db0aa2e9SDavid Howells 		if (remain)
188db0aa2e9SDavid Howells 			break;
189db0aa2e9SDavid Howells 	} while (len);
190db0aa2e9SDavid Howells 
191db0aa2e9SDavid Howells 	iter->folioq_slot = slot;
192db0aa2e9SDavid Howells 	iter->folioq = folioq;
193db0aa2e9SDavid Howells 	iter->iov_offset = skip;
194db0aa2e9SDavid Howells 	iter->count -= progress;
195db0aa2e9SDavid Howells 	return progress;
196db0aa2e9SDavid Howells }
197db0aa2e9SDavid Howells 
198db0aa2e9SDavid Howells /*
199f1982740SDavid Howells  * Handle ITER_XARRAY.
200f1982740SDavid Howells  */
201f1982740SDavid Howells static __always_inline
iterate_xarray(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)202f1982740SDavid Howells size_t iterate_xarray(struct iov_iter *iter, size_t len, void *priv, void *priv2,
203f1982740SDavid Howells 		      iov_step_f step)
204f1982740SDavid Howells {
205f1982740SDavid Howells 	struct folio *folio;
206f1982740SDavid Howells 	size_t progress = 0;
207f1982740SDavid Howells 	loff_t start = iter->xarray_start + iter->iov_offset;
208f1982740SDavid Howells 	pgoff_t index = start / PAGE_SIZE;
209f1982740SDavid Howells 	XA_STATE(xas, iter->xarray, index);
210f1982740SDavid Howells 
211f1982740SDavid Howells 	rcu_read_lock();
212f1982740SDavid Howells 	xas_for_each(&xas, folio, ULONG_MAX) {
213f1982740SDavid Howells 		size_t remain, consumed, offset, part, flen;
214f1982740SDavid Howells 
215f1982740SDavid Howells 		if (xas_retry(&xas, folio))
216f1982740SDavid Howells 			continue;
217f1982740SDavid Howells 		if (WARN_ON(xa_is_value(folio)))
218f1982740SDavid Howells 			break;
219f1982740SDavid Howells 		if (WARN_ON(folio_test_hugetlb(folio)))
220f1982740SDavid Howells 			break;
221f1982740SDavid Howells 
222f1982740SDavid Howells 		offset = offset_in_folio(folio, start + progress);
223f1982740SDavid Howells 		flen = min(folio_size(folio) - offset, len);
224f1982740SDavid Howells 
225f1982740SDavid Howells 		while (flen) {
226f1982740SDavid Howells 			void *base = kmap_local_folio(folio, offset);
227f1982740SDavid Howells 
228f1982740SDavid Howells 			part = min_t(size_t, flen,
229f1982740SDavid Howells 				     PAGE_SIZE - offset_in_page(offset));
230f1982740SDavid Howells 			remain = step(base, progress, part, priv, priv2);
231f1982740SDavid Howells 			kunmap_local(base);
232f1982740SDavid Howells 
233f1982740SDavid Howells 			consumed = part - remain;
234f1982740SDavid Howells 			progress += consumed;
235f1982740SDavid Howells 			len -= consumed;
236f1982740SDavid Howells 
237f1982740SDavid Howells 			if (remain || len == 0)
238f1982740SDavid Howells 				goto out;
239f1982740SDavid Howells 			flen -= consumed;
240f1982740SDavid Howells 			offset += consumed;
241f1982740SDavid Howells 		}
242f1982740SDavid Howells 	}
243f1982740SDavid Howells 
244f1982740SDavid Howells out:
245f1982740SDavid Howells 	rcu_read_unlock();
246f1982740SDavid Howells 	iter->iov_offset += progress;
247f1982740SDavid Howells 	iter->count -= progress;
248f1982740SDavid Howells 	return progress;
249f1982740SDavid Howells }
250f1982740SDavid Howells 
251f1982740SDavid Howells /*
252f1982740SDavid Howells  * Handle ITER_DISCARD.
253f1982740SDavid Howells  */
254f1982740SDavid Howells static __always_inline
iterate_discard(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)255f1982740SDavid Howells size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv2,
256f1982740SDavid Howells 		      iov_step_f step)
257f1982740SDavid Howells {
258f1982740SDavid Howells 	size_t progress = len;
259f1982740SDavid Howells 
260f1982740SDavid Howells 	iter->count -= progress;
261f1982740SDavid Howells 	return progress;
262f1982740SDavid Howells }
263f1982740SDavid Howells 
264f1982740SDavid Howells /**
265f1982740SDavid Howells  * iterate_and_advance2 - Iterate over an iterator
266f1982740SDavid Howells  * @iter: The iterator to iterate over.
267f1982740SDavid Howells  * @len: The amount to iterate over.
268f1982740SDavid Howells  * @priv: Data for the step functions.
269f1982740SDavid Howells  * @priv2: More data for the step functions.
270f1982740SDavid Howells  * @ustep: Function for UBUF/IOVEC iterators; given __user addresses.
271f1982740SDavid Howells  * @step: Function for other iterators; given kernel addresses.
272f1982740SDavid Howells  *
273f1982740SDavid Howells  * Iterate over the next part of an iterator, up to the specified length.  The
274f1982740SDavid Howells  * buffer is presented in segments, which for kernel iteration are broken up by
275f1982740SDavid Howells  * physical pages and mapped, with the mapped address being presented.
276f1982740SDavid Howells  *
277f1982740SDavid Howells  * Two step functions, @step and @ustep, must be provided, one for handling
278f1982740SDavid Howells  * mapped kernel addresses and the other is given user addresses which have the
279f1982740SDavid Howells  * potential to fault since no pinning is performed.
280f1982740SDavid Howells  *
281f1982740SDavid Howells  * The step functions are passed the address and length of the segment, @priv,
282f1982740SDavid Howells  * @priv2 and the amount of data so far iterated over (which can, for example,
283f1982740SDavid Howells  * be added to @priv to point to the right part of a second buffer).  The step
284f1982740SDavid Howells  * functions should return the amount of the segment they didn't process (ie. 0
285f1982740SDavid Howells  * indicates complete processsing).
286f1982740SDavid Howells  *
287f1982740SDavid Howells  * This function returns the amount of data processed (ie. 0 means nothing was
288f1982740SDavid Howells  * processed and the value of @len means processes to completion).
289f1982740SDavid Howells  */
290f1982740SDavid Howells static __always_inline
iterate_and_advance2(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_ustep_f ustep,iov_step_f step)291f1982740SDavid Howells size_t iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
292f1982740SDavid Howells 			    void *priv2, iov_ustep_f ustep, iov_step_f step)
293f1982740SDavid Howells {
294f1982740SDavid Howells 	if (unlikely(iter->count < len))
295f1982740SDavid Howells 		len = iter->count;
296f1982740SDavid Howells 	if (unlikely(!len))
297f1982740SDavid Howells 		return 0;
298f1982740SDavid Howells 
299f1982740SDavid Howells 	if (likely(iter_is_ubuf(iter)))
300f1982740SDavid Howells 		return iterate_ubuf(iter, len, priv, priv2, ustep);
301f1982740SDavid Howells 	if (likely(iter_is_iovec(iter)))
302f1982740SDavid Howells 		return iterate_iovec(iter, len, priv, priv2, ustep);
303f1982740SDavid Howells 	if (iov_iter_is_bvec(iter))
304f1982740SDavid Howells 		return iterate_bvec(iter, len, priv, priv2, step);
305f1982740SDavid Howells 	if (iov_iter_is_kvec(iter))
306f1982740SDavid Howells 		return iterate_kvec(iter, len, priv, priv2, step);
307db0aa2e9SDavid Howells 	if (iov_iter_is_folioq(iter))
308db0aa2e9SDavid Howells 		return iterate_folioq(iter, len, priv, priv2, step);
309f1982740SDavid Howells 	if (iov_iter_is_xarray(iter))
310f1982740SDavid Howells 		return iterate_xarray(iter, len, priv, priv2, step);
311f1982740SDavid Howells 	return iterate_discard(iter, len, priv, priv2, step);
312f1982740SDavid Howells }
313f1982740SDavid Howells 
314f1982740SDavid Howells /**
315f1982740SDavid Howells  * iterate_and_advance - Iterate over an iterator
316f1982740SDavid Howells  * @iter: The iterator to iterate over.
317f1982740SDavid Howells  * @len: The amount to iterate over.
318f1982740SDavid Howells  * @priv: Data for the step functions.
319f1982740SDavid Howells  * @ustep: Function for UBUF/IOVEC iterators; given __user addresses.
320f1982740SDavid Howells  * @step: Function for other iterators; given kernel addresses.
321f1982740SDavid Howells  *
322f1982740SDavid Howells  * As iterate_and_advance2(), but priv2 is always NULL.
323f1982740SDavid Howells  */
324f1982740SDavid Howells static __always_inline
iterate_and_advance(struct iov_iter * iter,size_t len,void * priv,iov_ustep_f ustep,iov_step_f step)325f1982740SDavid Howells size_t iterate_and_advance(struct iov_iter *iter, size_t len, void *priv,
326f1982740SDavid Howells 			   iov_ustep_f ustep, iov_step_f step)
327f1982740SDavid Howells {
328f1982740SDavid Howells 	return iterate_and_advance2(iter, len, priv, NULL, ustep, step);
329f1982740SDavid Howells }
330f1982740SDavid Howells 
331*2982c8c1SDavid Howells /**
332*2982c8c1SDavid Howells  * iterate_and_advance_kernel - Iterate over a kernel-internal iterator
333*2982c8c1SDavid Howells  * @iter: The iterator to iterate over.
334*2982c8c1SDavid Howells  * @len: The amount to iterate over.
335*2982c8c1SDavid Howells  * @priv: Data for the step functions.
336*2982c8c1SDavid Howells  * @priv2: More data for the step functions.
337*2982c8c1SDavid Howells  * @step: Function for other iterators; given kernel addresses.
338*2982c8c1SDavid Howells  *
339*2982c8c1SDavid Howells  * Iterate over the next part of an iterator, up to the specified length.  The
340*2982c8c1SDavid Howells  * buffer is presented in segments, which for kernel iteration are broken up by
341*2982c8c1SDavid Howells  * physical pages and mapped, with the mapped address being presented.
342*2982c8c1SDavid Howells  *
343*2982c8c1SDavid Howells  * [!] Note This will only handle BVEC, KVEC, FOLIOQ, XARRAY and DISCARD-type
344*2982c8c1SDavid Howells  * iterators; it will not handle UBUF or IOVEC-type iterators.
345*2982c8c1SDavid Howells  *
346*2982c8c1SDavid Howells  * A step functions, @step, must be provided, one for handling mapped kernel
347*2982c8c1SDavid Howells  * addresses and the other is given user addresses which have the potential to
348*2982c8c1SDavid Howells  * fault since no pinning is performed.
349*2982c8c1SDavid Howells  *
350*2982c8c1SDavid Howells  * The step functions are passed the address and length of the segment, @priv,
351*2982c8c1SDavid Howells  * @priv2 and the amount of data so far iterated over (which can, for example,
352*2982c8c1SDavid Howells  * be added to @priv to point to the right part of a second buffer).  The step
353*2982c8c1SDavid Howells  * functions should return the amount of the segment they didn't process (ie. 0
354*2982c8c1SDavid Howells  * indicates complete processsing).
355*2982c8c1SDavid Howells  *
356*2982c8c1SDavid Howells  * This function returns the amount of data processed (ie. 0 means nothing was
357*2982c8c1SDavid Howells  * processed and the value of @len means processes to completion).
358*2982c8c1SDavid Howells  */
359*2982c8c1SDavid Howells static __always_inline
iterate_and_advance_kernel(struct iov_iter * iter,size_t len,void * priv,void * priv2,iov_step_f step)360*2982c8c1SDavid Howells size_t iterate_and_advance_kernel(struct iov_iter *iter, size_t len, void *priv,
361*2982c8c1SDavid Howells 				  void *priv2, iov_step_f step)
362*2982c8c1SDavid Howells {
363*2982c8c1SDavid Howells 	if (unlikely(iter->count < len))
364*2982c8c1SDavid Howells 		len = iter->count;
365*2982c8c1SDavid Howells 	if (unlikely(!len))
366*2982c8c1SDavid Howells 		return 0;
367*2982c8c1SDavid Howells 	if (iov_iter_is_bvec(iter))
368*2982c8c1SDavid Howells 		return iterate_bvec(iter, len, priv, priv2, step);
369*2982c8c1SDavid Howells 	if (iov_iter_is_kvec(iter))
370*2982c8c1SDavid Howells 		return iterate_kvec(iter, len, priv, priv2, step);
371*2982c8c1SDavid Howells 	if (iov_iter_is_folioq(iter))
372*2982c8c1SDavid Howells 		return iterate_folioq(iter, len, priv, priv2, step);
373*2982c8c1SDavid Howells 	if (iov_iter_is_xarray(iter))
374*2982c8c1SDavid Howells 		return iterate_xarray(iter, len, priv, priv2, step);
375*2982c8c1SDavid Howells 	return iterate_discard(iter, len, priv, priv2, step);
376*2982c8c1SDavid Howells }
377*2982c8c1SDavid Howells 
378f1982740SDavid Howells #endif /* _LINUX_IOV_ITER_H */
379