1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/* I/O iterator iteration building functions.
3 *
4 * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8#ifndef _LINUX_IOV_ITER_H
9#define _LINUX_IOV_ITER_H
10
11#include <linux/uio.h>
12#include <linux/bvec.h>
13
14typedef size_t (*iov_step_f)(void *iter_base, size_t progress, size_t len,
15			     void *priv, void *priv2);
16typedef size_t (*iov_ustep_f)(void __user *iter_base, size_t progress, size_t len,
17			      void *priv, void *priv2);
18
19/*
20 * Handle ITER_UBUF.
21 */
22static __always_inline
23size_t iterate_ubuf(struct iov_iter *iter, size_t len, void *priv, void *priv2,
24		    iov_ustep_f step)
25{
26	void __user *base = iter->ubuf;
27	size_t progress = 0, remain;
28
29	remain = step(base + iter->iov_offset, 0, len, priv, priv2);
30	progress = len - remain;
31	iter->iov_offset += progress;
32	iter->count -= progress;
33	return progress;
34}
35
36/*
37 * Handle ITER_IOVEC.
38 */
39static __always_inline
40size_t iterate_iovec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
41		     iov_ustep_f step)
42{
43	const struct iovec *p = iter->__iov;
44	size_t progress = 0, skip = iter->iov_offset;
45
46	do {
47		size_t remain, consumed;
48		size_t part = min(len, p->iov_len - skip);
49
50		if (likely(part)) {
51			remain = step(p->iov_base + skip, progress, part, priv, priv2);
52			consumed = part - remain;
53			progress += consumed;
54			skip += consumed;
55			len -= consumed;
56			if (skip < p->iov_len)
57				break;
58		}
59		p++;
60		skip = 0;
61	} while (len);
62
63	iter->nr_segs -= p - iter->__iov;
64	iter->__iov = p;
65	iter->iov_offset = skip;
66	iter->count -= progress;
67	return progress;
68}
69
70/*
71 * Handle ITER_KVEC.
72 */
73static __always_inline
74size_t iterate_kvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
75		    iov_step_f step)
76{
77	const struct kvec *p = iter->kvec;
78	size_t progress = 0, skip = iter->iov_offset;
79
80	do {
81		size_t remain, consumed;
82		size_t part = min(len, p->iov_len - skip);
83
84		if (likely(part)) {
85			remain = step(p->iov_base + skip, progress, part, priv, priv2);
86			consumed = part - remain;
87			progress += consumed;
88			skip += consumed;
89			len -= consumed;
90			if (skip < p->iov_len)
91				break;
92		}
93		p++;
94		skip = 0;
95	} while (len);
96
97	iter->nr_segs -= p - iter->kvec;
98	iter->kvec = p;
99	iter->iov_offset = skip;
100	iter->count -= progress;
101	return progress;
102}
103
104/*
105 * Handle ITER_BVEC.
106 */
107static __always_inline
108size_t iterate_bvec(struct iov_iter *iter, size_t len, void *priv, void *priv2,
109		    iov_step_f step)
110{
111	const struct bio_vec *p = iter->bvec;
112	size_t progress = 0, skip = iter->iov_offset;
113
114	do {
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);
118
119		part = min3(len,
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);
123		kunmap_local(kaddr);
124		consumed = part - remain;
125		len -= consumed;
126		progress += consumed;
127		skip += consumed;
128		if (skip >= p->bv_len) {
129			skip = 0;
130			p++;
131		}
132		if (remain)
133			break;
134	} while (len);
135
136	iter->nr_segs -= p - iter->bvec;
137	iter->bvec = p;
138	iter->iov_offset = skip;
139	iter->count -= progress;
140	return progress;
141}
142
143/*
144 * Handle ITER_XARRAY.
145 */
146static __always_inline
147size_t iterate_xarray(struct iov_iter *iter, size_t len, void *priv, void *priv2,
148		      iov_step_f step)
149{
150	struct folio *folio;
151	size_t progress = 0;
152	loff_t start = iter->xarray_start + iter->iov_offset;
153	pgoff_t index = start / PAGE_SIZE;
154	XA_STATE(xas, iter->xarray, index);
155
156	rcu_read_lock();
157	xas_for_each(&xas, folio, ULONG_MAX) {
158		size_t remain, consumed, offset, part, flen;
159
160		if (xas_retry(&xas, folio))
161			continue;
162		if (WARN_ON(xa_is_value(folio)))
163			break;
164		if (WARN_ON(folio_test_hugetlb(folio)))
165			break;
166
167		offset = offset_in_folio(folio, start + progress);
168		flen = min(folio_size(folio) - offset, len);
169
170		while (flen) {
171			void *base = kmap_local_folio(folio, offset);
172
173			part = min_t(size_t, flen,
174				     PAGE_SIZE - offset_in_page(offset));
175			remain = step(base, progress, part, priv, priv2);
176			kunmap_local(base);
177
178			consumed = part - remain;
179			progress += consumed;
180			len -= consumed;
181
182			if (remain || len == 0)
183				goto out;
184			flen -= consumed;
185			offset += consumed;
186		}
187	}
188
189out:
190	rcu_read_unlock();
191	iter->iov_offset += progress;
192	iter->count -= progress;
193	return progress;
194}
195
196/*
197 * Handle ITER_DISCARD.
198 */
199static __always_inline
200size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv2,
201		      iov_step_f step)
202{
203	size_t progress = len;
204
205	iter->count -= progress;
206	return progress;
207}
208
209/**
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.
217 *
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.
221 *
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.
225 *
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).
231 *
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).
234 */
235static __always_inline
236size_t iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
237			    void *priv2, iov_ustep_f ustep, iov_step_f step)
238{
239	if (unlikely(iter->count < len))
240		len = iter->count;
241	if (unlikely(!len))
242		return 0;
243
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);
255}
256
257/**
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.
264 *
265 * As iterate_and_advance2(), but priv2 is always NULL.
266 */
267static __always_inline
268size_t iterate_and_advance(struct iov_iter *iter, size_t len, void *priv,
269			   iov_ustep_f ustep, iov_step_f step)
270{
271	return iterate_and_advance2(iter, len, priv, NULL, ustep, step);
272}
273
274#endif /* _LINUX_IOV_ITER_H */
275