xref: /freebsd-src/sys/contrib/openzfs/lib/libzpool/abd_os.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1e2df9bb4SMartin Matuska /*
2e2df9bb4SMartin Matuska  * CDDL HEADER START
3e2df9bb4SMartin Matuska  *
4e2df9bb4SMartin Matuska  * The contents of this file are subject to the terms of the
5e2df9bb4SMartin Matuska  * Common Development and Distribution License (the "License").
6e2df9bb4SMartin Matuska  * You may not use this file except in compliance with the License.
7e2df9bb4SMartin Matuska  *
8e2df9bb4SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e2df9bb4SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10e2df9bb4SMartin Matuska  * See the License for the specific language governing permissions
11e2df9bb4SMartin Matuska  * and limitations under the License.
12e2df9bb4SMartin Matuska  *
13e2df9bb4SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14e2df9bb4SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e2df9bb4SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16e2df9bb4SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17e2df9bb4SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18e2df9bb4SMartin Matuska  *
19e2df9bb4SMartin Matuska  * CDDL HEADER END
20e2df9bb4SMartin Matuska  */
21e2df9bb4SMartin Matuska /*
22e2df9bb4SMartin Matuska  * Copyright (c) 2014 by Chunwei Chen. All rights reserved.
23e2df9bb4SMartin Matuska  * Copyright (c) 2019 by Delphix. All rights reserved.
24e2df9bb4SMartin Matuska  * Copyright (c) 2023, 2024, Klara Inc.
25e2df9bb4SMartin Matuska  */
26e2df9bb4SMartin Matuska 
27e2df9bb4SMartin Matuska #include <sys/abd_impl.h>
28e2df9bb4SMartin Matuska #include <sys/param.h>
29e2df9bb4SMartin Matuska #include <sys/zio.h>
30e2df9bb4SMartin Matuska #include <sys/arc.h>
31e2df9bb4SMartin Matuska #include <sys/zfs_context.h>
32e2df9bb4SMartin Matuska #include <sys/zfs_znode.h>
33e2df9bb4SMartin Matuska 
34e2df9bb4SMartin Matuska /*
35e2df9bb4SMartin Matuska  * We're simulating scatter/gather with 4K allocations, since that's more like
36e2df9bb4SMartin Matuska  * what a typical kernel does.
37e2df9bb4SMartin Matuska  */
38e2df9bb4SMartin Matuska #define	ABD_PAGESIZE	(4096)
39e2df9bb4SMartin Matuska #define	ABD_PAGESHIFT	(12)
40e2df9bb4SMartin Matuska #define	ABD_PAGEMASK	(ABD_PAGESIZE-1)
41e2df9bb4SMartin Matuska 
42e2df9bb4SMartin Matuska /*
43e2df9bb4SMartin Matuska  * See rationale in module/os/linux/zfs/abd_os.c, but in userspace this is
44e2df9bb4SMartin Matuska  * mostly useful to get a mix of linear and scatter ABDs for testing.
45e2df9bb4SMartin Matuska  */
46e2df9bb4SMartin Matuska #define	ABD_SCATTER_MIN_SIZE	(512 * 3)
47e2df9bb4SMartin Matuska 
48e2df9bb4SMartin Matuska abd_t *abd_zero_scatter = NULL;
49e2df9bb4SMartin Matuska 
50e2df9bb4SMartin Matuska static uint_t
51e2df9bb4SMartin Matuska abd_iovcnt_for_bytes(size_t size)
52e2df9bb4SMartin Matuska {
53e2df9bb4SMartin Matuska 	/*
54e2df9bb4SMartin Matuska 	 * Each iovec points to a 4K page. There's no real reason to do this
55e2df9bb4SMartin Matuska 	 * in userspace, but our whole point here is to make it feel a bit
56e2df9bb4SMartin Matuska 	 * more like a real paged memory model.
57e2df9bb4SMartin Matuska 	 */
58e2df9bb4SMartin Matuska 	return (P2ROUNDUP(size, ABD_PAGESIZE) / ABD_PAGESIZE);
59e2df9bb4SMartin Matuska }
60e2df9bb4SMartin Matuska 
61e2df9bb4SMartin Matuska abd_t *
62e2df9bb4SMartin Matuska abd_alloc_struct_impl(size_t size)
63e2df9bb4SMartin Matuska {
64e2df9bb4SMartin Matuska 	/*
65e2df9bb4SMartin Matuska 	 * Zero-sized means it will be used for a linear or gang abd, so just
66e2df9bb4SMartin Matuska 	 * allocate the abd itself and return.
67e2df9bb4SMartin Matuska 	 */
68e2df9bb4SMartin Matuska 	if (size == 0)
69e2df9bb4SMartin Matuska 		return (umem_alloc(sizeof (abd_t), UMEM_NOFAIL));
70e2df9bb4SMartin Matuska 
71e2df9bb4SMartin Matuska 	/*
72e2df9bb4SMartin Matuska 	 * Allocating for a scatter abd, so compute how many ABD_PAGESIZE
73e2df9bb4SMartin Matuska 	 * iovecs we will need to hold this size. Append that allocation to the
74e2df9bb4SMartin Matuska 	 * end. Note that struct abd_scatter has includes abd_iov[1], so we
75e2df9bb4SMartin Matuska 	 * allocate one less iovec than we need.
76e2df9bb4SMartin Matuska 	 *
77e2df9bb4SMartin Matuska 	 * Note we're not allocating the pages proper, just the iovec pointers.
78e2df9bb4SMartin Matuska 	 * That's down in abd_alloc_chunks. We _could_ do it here in a single
79e2df9bb4SMartin Matuska 	 * allocation, but it's fiddly and harder to read for no real gain.
80e2df9bb4SMartin Matuska 	 */
81e2df9bb4SMartin Matuska 	uint_t n = abd_iovcnt_for_bytes(size);
82e2df9bb4SMartin Matuska 	abd_t *abd = umem_alloc(sizeof (abd_t) + (n-1) * sizeof (struct iovec),
83e2df9bb4SMartin Matuska 	    UMEM_NOFAIL);
84e2df9bb4SMartin Matuska 	ABD_SCATTER(abd).abd_offset = 0;
85e2df9bb4SMartin Matuska 	ABD_SCATTER(abd).abd_iovcnt = n;
86e2df9bb4SMartin Matuska 	return (abd);
87e2df9bb4SMartin Matuska }
88e2df9bb4SMartin Matuska 
89e2df9bb4SMartin Matuska void
90e2df9bb4SMartin Matuska abd_free_struct_impl(abd_t *abd)
91e2df9bb4SMartin Matuska {
92e2df9bb4SMartin Matuska 	/* For scatter, compute the extra amount we need to free */
93e2df9bb4SMartin Matuska 	uint_t iovcnt =
94e2df9bb4SMartin Matuska 	    abd_is_linear(abd) || abd_is_gang(abd) ?
95e2df9bb4SMartin Matuska 	    0 : (ABD_SCATTER(abd).abd_iovcnt - 1);
96e2df9bb4SMartin Matuska 	umem_free(abd, sizeof (abd_t) + iovcnt * sizeof (struct iovec));
97e2df9bb4SMartin Matuska }
98e2df9bb4SMartin Matuska 
99e2df9bb4SMartin Matuska void
100e2df9bb4SMartin Matuska abd_alloc_chunks(abd_t *abd, size_t size)
101e2df9bb4SMartin Matuska {
102e2df9bb4SMartin Matuska 	/*
103e2df9bb4SMartin Matuska 	 * We've already allocated the iovec array; ensure that the wanted size
104e2df9bb4SMartin Matuska 	 * actually matches, otherwise the caller has made a mistake somewhere.
105e2df9bb4SMartin Matuska 	 */
106e2df9bb4SMartin Matuska 	uint_t n = ABD_SCATTER(abd).abd_iovcnt;
107e2df9bb4SMartin Matuska 	ASSERT3U(n, ==, abd_iovcnt_for_bytes(size));
108e2df9bb4SMartin Matuska 
109e2df9bb4SMartin Matuska 	/*
110e2df9bb4SMartin Matuska 	 * Allocate a ABD_PAGESIZE region for each iovec.
111e2df9bb4SMartin Matuska 	 */
112e2df9bb4SMartin Matuska 	struct iovec *iov = ABD_SCATTER(abd).abd_iov;
113e2df9bb4SMartin Matuska 	for (int i = 0; i < n; i++) {
114e2df9bb4SMartin Matuska 		iov[i].iov_base =
115e2df9bb4SMartin Matuska 		    umem_alloc_aligned(ABD_PAGESIZE, ABD_PAGESIZE, UMEM_NOFAIL);
116e2df9bb4SMartin Matuska 		iov[i].iov_len = ABD_PAGESIZE;
117e2df9bb4SMartin Matuska 	}
118e2df9bb4SMartin Matuska }
119e2df9bb4SMartin Matuska 
120e2df9bb4SMartin Matuska void
121e2df9bb4SMartin Matuska abd_free_chunks(abd_t *abd)
122e2df9bb4SMartin Matuska {
123e2df9bb4SMartin Matuska 	uint_t n = ABD_SCATTER(abd).abd_iovcnt;
124e2df9bb4SMartin Matuska 	struct iovec *iov = ABD_SCATTER(abd).abd_iov;
125e2df9bb4SMartin Matuska 	for (int i = 0; i < n; i++)
126e2df9bb4SMartin Matuska 		umem_free_aligned(iov[i].iov_base, ABD_PAGESIZE);
127e2df9bb4SMartin Matuska }
128e2df9bb4SMartin Matuska 
129e2df9bb4SMartin Matuska boolean_t
130e2df9bb4SMartin Matuska abd_size_alloc_linear(size_t size)
131e2df9bb4SMartin Matuska {
132e2df9bb4SMartin Matuska 	return (size < ABD_SCATTER_MIN_SIZE);
133e2df9bb4SMartin Matuska }
134e2df9bb4SMartin Matuska 
135e2df9bb4SMartin Matuska void
136e2df9bb4SMartin Matuska abd_update_scatter_stats(abd_t *abd, abd_stats_op_t op)
137e2df9bb4SMartin Matuska {
138e2df9bb4SMartin Matuska 	ASSERT(op == ABDSTAT_INCR || op == ABDSTAT_DECR);
139e2df9bb4SMartin Matuska 	int waste = P2ROUNDUP(abd->abd_size, ABD_PAGESIZE) - abd->abd_size;
140e2df9bb4SMartin Matuska 	if (op == ABDSTAT_INCR) {
141e2df9bb4SMartin Matuska 		arc_space_consume(waste, ARC_SPACE_ABD_CHUNK_WASTE);
142e2df9bb4SMartin Matuska 	} else {
143e2df9bb4SMartin Matuska 		arc_space_return(waste, ARC_SPACE_ABD_CHUNK_WASTE);
144e2df9bb4SMartin Matuska 	}
145e2df9bb4SMartin Matuska }
146e2df9bb4SMartin Matuska 
147e2df9bb4SMartin Matuska void
148e2df9bb4SMartin Matuska abd_update_linear_stats(abd_t *abd, abd_stats_op_t op)
149e2df9bb4SMartin Matuska {
150e2df9bb4SMartin Matuska 	(void) abd;
151e2df9bb4SMartin Matuska 	(void) op;
152e2df9bb4SMartin Matuska 	ASSERT(op == ABDSTAT_INCR || op == ABDSTAT_DECR);
153e2df9bb4SMartin Matuska }
154e2df9bb4SMartin Matuska 
155e2df9bb4SMartin Matuska void
156e2df9bb4SMartin Matuska abd_verify_scatter(abd_t *abd)
157e2df9bb4SMartin Matuska {
158e2df9bb4SMartin Matuska #ifdef ZFS_DEBUG
159e2df9bb4SMartin Matuska 	/*
160e2df9bb4SMartin Matuska 	 * scatter abds shall have:
161e2df9bb4SMartin Matuska 	 * - at least one iovec
162e2df9bb4SMartin Matuska 	 * - all iov_base point somewhere
163e2df9bb4SMartin Matuska 	 * - all iov_len are ABD_PAGESIZE
164e2df9bb4SMartin Matuska 	 * - offset set within the abd pages somewhere
165e2df9bb4SMartin Matuska 	 */
166e2df9bb4SMartin Matuska 	uint_t n = ABD_SCATTER(abd).abd_iovcnt;
167e2df9bb4SMartin Matuska 	ASSERT3U(n, >, 0);
168e2df9bb4SMartin Matuska 
169e2df9bb4SMartin Matuska 	uint_t len = 0;
170e2df9bb4SMartin Matuska 	for (int i = 0; i < n; i++) {
171e2df9bb4SMartin Matuska 		ASSERT3P(ABD_SCATTER(abd).abd_iov[i].iov_base, !=, NULL);
172e2df9bb4SMartin Matuska 		ASSERT3U(ABD_SCATTER(abd).abd_iov[i].iov_len, ==, ABD_PAGESIZE);
173e2df9bb4SMartin Matuska 		len += ABD_PAGESIZE;
174e2df9bb4SMartin Matuska 	}
175e2df9bb4SMartin Matuska 
176e2df9bb4SMartin Matuska 	ASSERT3U(ABD_SCATTER(abd).abd_offset, <, len);
177e2df9bb4SMartin Matuska #endif
178e2df9bb4SMartin Matuska }
179e2df9bb4SMartin Matuska 
180e2df9bb4SMartin Matuska void
181e2df9bb4SMartin Matuska abd_init(void)
182e2df9bb4SMartin Matuska {
183e2df9bb4SMartin Matuska 	/*
184e2df9bb4SMartin Matuska 	 * Create the "zero" scatter abd. This is always the size of the
185e2df9bb4SMartin Matuska 	 * largest possible block, but only actually has a single allocated
186e2df9bb4SMartin Matuska 	 * page, which all iovecs in the abd point to.
187e2df9bb4SMartin Matuska 	 */
188e2df9bb4SMartin Matuska 	abd_zero_scatter = abd_alloc_struct(SPA_MAXBLOCKSIZE);
189e2df9bb4SMartin Matuska 	abd_zero_scatter->abd_flags |= ABD_FLAG_OWNER;
190e2df9bb4SMartin Matuska 	abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE;
191e2df9bb4SMartin Matuska 
192e2df9bb4SMartin Matuska 	void *zero =
193e2df9bb4SMartin Matuska 	    umem_alloc_aligned(ABD_PAGESIZE, ABD_PAGESIZE, UMEM_NOFAIL);
194e2df9bb4SMartin Matuska 	memset(zero, 0, ABD_PAGESIZE);
195e2df9bb4SMartin Matuska 
196e2df9bb4SMartin Matuska 	uint_t n = abd_iovcnt_for_bytes(SPA_MAXBLOCKSIZE);
197e2df9bb4SMartin Matuska 	struct iovec *iov = ABD_SCATTER(abd_zero_scatter).abd_iov;
198e2df9bb4SMartin Matuska 	for (int i = 0; i < n; i++) {
199e2df9bb4SMartin Matuska 		iov[i].iov_base = zero;
200e2df9bb4SMartin Matuska 		iov[i].iov_len = ABD_PAGESIZE;
201e2df9bb4SMartin Matuska 	}
202e2df9bb4SMartin Matuska }
203e2df9bb4SMartin Matuska 
204e2df9bb4SMartin Matuska void
205e2df9bb4SMartin Matuska abd_fini(void)
206e2df9bb4SMartin Matuska {
207e2df9bb4SMartin Matuska 	umem_free_aligned(
208e2df9bb4SMartin Matuska 	    ABD_SCATTER(abd_zero_scatter).abd_iov[0].iov_base, ABD_PAGESIZE);
209e2df9bb4SMartin Matuska 	abd_free_struct(abd_zero_scatter);
210e2df9bb4SMartin Matuska 	abd_zero_scatter = NULL;
211e2df9bb4SMartin Matuska }
212e2df9bb4SMartin Matuska 
213e2df9bb4SMartin Matuska void
214e2df9bb4SMartin Matuska abd_free_linear_page(abd_t *abd)
215e2df9bb4SMartin Matuska {
216e2df9bb4SMartin Matuska 	/*
217e2df9bb4SMartin Matuska 	 * LINEAR_PAGE is specific to the Linux kernel; we never set this
218e2df9bb4SMartin Matuska 	 * flag, so this will never be called.
219e2df9bb4SMartin Matuska 	 */
220e2df9bb4SMartin Matuska 	(void) abd;
221e2df9bb4SMartin Matuska 	PANIC("unreachable");
222e2df9bb4SMartin Matuska }
223e2df9bb4SMartin Matuska 
224e2df9bb4SMartin Matuska abd_t *
225e2df9bb4SMartin Matuska abd_alloc_for_io(size_t size, boolean_t is_metadata)
226e2df9bb4SMartin Matuska {
227e2df9bb4SMartin Matuska 	return (abd_alloc(size, is_metadata));
228e2df9bb4SMartin Matuska }
229e2df9bb4SMartin Matuska 
230e2df9bb4SMartin Matuska abd_t *
231e2df9bb4SMartin Matuska abd_get_offset_scatter(abd_t *dabd, abd_t *sabd, size_t off, size_t size)
232e2df9bb4SMartin Matuska {
233e2df9bb4SMartin Matuska 
234e2df9bb4SMartin Matuska 	/*
235e2df9bb4SMartin Matuska 	 * Create a new scatter dabd by borrowing data pages from sabd to cover
236e2df9bb4SMartin Matuska 	 * off+size.
237e2df9bb4SMartin Matuska 	 *
238e2df9bb4SMartin Matuska 	 * sabd is an existing scatter abd with a set of iovecs, each covering
239e2df9bb4SMartin Matuska 	 * an ABD_PAGESIZE (4K) allocation. It's "zero" is at abd_offset.
240e2df9bb4SMartin Matuska 	 *
241e2df9bb4SMartin Matuska 	 *   [........][........][........][........]
242e2df9bb4SMartin Matuska 	 *      ^- sabd_offset
243e2df9bb4SMartin Matuska 	 *
244e2df9bb4SMartin Matuska 	 * We want to produce a new abd, referencing those allocations at the
245e2df9bb4SMartin Matuska 	 * given offset.
246e2df9bb4SMartin Matuska 	 *
247e2df9bb4SMartin Matuska 	 *   [........][........][........][........]
248e2df9bb4SMartin Matuska 	 *                    ^- dabd_offset = sabd_offset + off
249e2df9bb4SMartin Matuska 	 *                                        ^- dabd_offset + size
250e2df9bb4SMartin Matuska 	 *
251e2df9bb4SMartin Matuska 	 * In this example, dabd needs three iovecs. The first iovec is offset
252e2df9bb4SMartin Matuska 	 * 0, so the final dabd_offset is masked back into the first iovec.
253e2df9bb4SMartin Matuska 	 *
254e2df9bb4SMartin Matuska 	 *             [........][........][........]
255e2df9bb4SMartin Matuska 	 *                    ^- dabd_offset
256e2df9bb4SMartin Matuska 	 */
257e2df9bb4SMartin Matuska 	size_t soff = ABD_SCATTER(sabd).abd_offset + off;
258e2df9bb4SMartin Matuska 	size_t doff = soff & ABD_PAGEMASK;
259e2df9bb4SMartin Matuska 	size_t iovcnt = abd_iovcnt_for_bytes(doff + size);
260e2df9bb4SMartin Matuska 
261e2df9bb4SMartin Matuska 	/*
262e2df9bb4SMartin Matuska 	 * If the passed-in abd has enough allocated iovecs already, reuse it.
263e2df9bb4SMartin Matuska 	 * Otherwise, make a new one. The caller will free the original if the
264e2df9bb4SMartin Matuska 	 * one it gets back is not the same.
265e2df9bb4SMartin Matuska 	 *
266e2df9bb4SMartin Matuska 	 * Note that it's ok if we reuse an abd with more iovecs than we need.
267e2df9bb4SMartin Matuska 	 * abd_size has the usable amount of data, and the abd does not own the
268e2df9bb4SMartin Matuska 	 * pages referenced by the iovecs. At worst, they're holding dangling
269e2df9bb4SMartin Matuska 	 * pointers that we'll never use anyway.
270e2df9bb4SMartin Matuska 	 */
271e2df9bb4SMartin Matuska 	if (dabd == NULL || ABD_SCATTER(dabd).abd_iovcnt < iovcnt)
272e2df9bb4SMartin Matuska 		dabd = abd_alloc_struct(iovcnt << ABD_PAGESHIFT);
273e2df9bb4SMartin Matuska 
274e2df9bb4SMartin Matuska 	/* Set offset into first page in view */
275e2df9bb4SMartin Matuska 	ABD_SCATTER(dabd).abd_offset = doff;
276e2df9bb4SMartin Matuska 
277e2df9bb4SMartin Matuska 	/* Copy the wanted iovecs from the source to the dest */
278e2df9bb4SMartin Matuska 	memcpy(&ABD_SCATTER(dabd).abd_iov[0],
279e2df9bb4SMartin Matuska 	    &ABD_SCATTER(sabd).abd_iov[soff >> ABD_PAGESHIFT],
280e2df9bb4SMartin Matuska 	    iovcnt * sizeof (struct iovec));
281e2df9bb4SMartin Matuska 
282e2df9bb4SMartin Matuska 	return (dabd);
283e2df9bb4SMartin Matuska }
284e2df9bb4SMartin Matuska 
285e2df9bb4SMartin Matuska void
286e2df9bb4SMartin Matuska abd_iter_init(struct abd_iter *aiter, abd_t *abd)
287e2df9bb4SMartin Matuska {
288e2df9bb4SMartin Matuska 	ASSERT(!abd_is_gang(abd));
289e2df9bb4SMartin Matuska 	abd_verify(abd);
290e2df9bb4SMartin Matuska 	memset(aiter, 0, sizeof (struct abd_iter));
291e2df9bb4SMartin Matuska 	aiter->iter_abd = abd;
292e2df9bb4SMartin Matuska }
293e2df9bb4SMartin Matuska 
294e2df9bb4SMartin Matuska boolean_t
295e2df9bb4SMartin Matuska abd_iter_at_end(struct abd_iter *aiter)
296e2df9bb4SMartin Matuska {
297e2df9bb4SMartin Matuska 	ASSERT3U(aiter->iter_pos, <=, aiter->iter_abd->abd_size);
298e2df9bb4SMartin Matuska 	return (aiter->iter_pos == aiter->iter_abd->abd_size);
299e2df9bb4SMartin Matuska }
300e2df9bb4SMartin Matuska 
301e2df9bb4SMartin Matuska void
302e2df9bb4SMartin Matuska abd_iter_advance(struct abd_iter *aiter, size_t amount)
303e2df9bb4SMartin Matuska {
304e2df9bb4SMartin Matuska 	ASSERT3P(aiter->iter_mapaddr, ==, NULL);
305e2df9bb4SMartin Matuska 	ASSERT0(aiter->iter_mapsize);
306e2df9bb4SMartin Matuska 
307e2df9bb4SMartin Matuska 	if (abd_iter_at_end(aiter))
308e2df9bb4SMartin Matuska 		return;
309e2df9bb4SMartin Matuska 
310e2df9bb4SMartin Matuska 	aiter->iter_pos += amount;
311e2df9bb4SMartin Matuska 	ASSERT3U(aiter->iter_pos, <=, aiter->iter_abd->abd_size);
312e2df9bb4SMartin Matuska }
313e2df9bb4SMartin Matuska 
314e2df9bb4SMartin Matuska void
315e2df9bb4SMartin Matuska abd_iter_map(struct abd_iter *aiter)
316e2df9bb4SMartin Matuska {
317e2df9bb4SMartin Matuska 	ASSERT3P(aiter->iter_mapaddr, ==, NULL);
318e2df9bb4SMartin Matuska 	ASSERT0(aiter->iter_mapsize);
319e2df9bb4SMartin Matuska 
320e2df9bb4SMartin Matuska 	if (abd_iter_at_end(aiter))
321e2df9bb4SMartin Matuska 		return;
322e2df9bb4SMartin Matuska 
323e2df9bb4SMartin Matuska 	if (abd_is_linear(aiter->iter_abd)) {
324e2df9bb4SMartin Matuska 		aiter->iter_mapaddr =
325e2df9bb4SMartin Matuska 		    ABD_LINEAR_BUF(aiter->iter_abd) + aiter->iter_pos;
326e2df9bb4SMartin Matuska 		aiter->iter_mapsize =
327e2df9bb4SMartin Matuska 		    aiter->iter_abd->abd_size - aiter->iter_pos;
328e2df9bb4SMartin Matuska 		return;
329e2df9bb4SMartin Matuska 	}
330e2df9bb4SMartin Matuska 
331e2df9bb4SMartin Matuska 	/*
332e2df9bb4SMartin Matuska 	 * For scatter, we index into the appropriate iovec, and return the
333e2df9bb4SMartin Matuska 	 * smaller of the amount requested, or up to the end of the page.
334e2df9bb4SMartin Matuska 	 */
335e2df9bb4SMartin Matuska 	size_t poff = aiter->iter_pos + ABD_SCATTER(aiter->iter_abd).abd_offset;
336e2df9bb4SMartin Matuska 
337e2df9bb4SMartin Matuska 	ASSERT3U(poff >> ABD_PAGESHIFT, <=,
338e2df9bb4SMartin Matuska 	    ABD_SCATTER(aiter->iter_abd).abd_iovcnt);
339e2df9bb4SMartin Matuska 	struct iovec *iov = &ABD_SCATTER(aiter->iter_abd).
340e2df9bb4SMartin Matuska 	    abd_iov[poff >> ABD_PAGESHIFT];
341e2df9bb4SMartin Matuska 
342e2df9bb4SMartin Matuska 	aiter->iter_mapsize = MIN(ABD_PAGESIZE - (poff & ABD_PAGEMASK),
343e2df9bb4SMartin Matuska 	    aiter->iter_abd->abd_size - aiter->iter_pos);
344e2df9bb4SMartin Matuska 	ASSERT3U(aiter->iter_mapsize, <=, ABD_PAGESIZE);
345e2df9bb4SMartin Matuska 
346e2df9bb4SMartin Matuska 	aiter->iter_mapaddr = iov->iov_base + (poff & ABD_PAGEMASK);
347e2df9bb4SMartin Matuska }
348e2df9bb4SMartin Matuska 
349e2df9bb4SMartin Matuska void
350e2df9bb4SMartin Matuska abd_iter_unmap(struct abd_iter *aiter)
351e2df9bb4SMartin Matuska {
352e2df9bb4SMartin Matuska 	if (abd_iter_at_end(aiter))
353e2df9bb4SMartin Matuska 		return;
354e2df9bb4SMartin Matuska 
355e2df9bb4SMartin Matuska 	ASSERT3P(aiter->iter_mapaddr, !=, NULL);
356e2df9bb4SMartin Matuska 	ASSERT3U(aiter->iter_mapsize, >, 0);
357e2df9bb4SMartin Matuska 
358e2df9bb4SMartin Matuska 	aiter->iter_mapaddr = NULL;
359e2df9bb4SMartin Matuska 	aiter->iter_mapsize = 0;
360e2df9bb4SMartin Matuska }
361e2df9bb4SMartin Matuska 
362e2df9bb4SMartin Matuska void
363e2df9bb4SMartin Matuska abd_cache_reap_now(void)
364e2df9bb4SMartin Matuska {
365e2df9bb4SMartin Matuska }
366*7a7741afSMartin Matuska 
367*7a7741afSMartin Matuska /*
368*7a7741afSMartin Matuska  * Borrow a raw buffer from an ABD without copying the contents of the ABD
369*7a7741afSMartin Matuska  * into the buffer. If the ABD is scattered, this will alloate a raw buffer
370*7a7741afSMartin Matuska  * whose contents are undefined. To copy over the existing data in the ABD, use
371*7a7741afSMartin Matuska  * abd_borrow_buf_copy() instead.
372*7a7741afSMartin Matuska  */
373*7a7741afSMartin Matuska void *
374*7a7741afSMartin Matuska abd_borrow_buf(abd_t *abd, size_t n)
375*7a7741afSMartin Matuska {
376*7a7741afSMartin Matuska 	void *buf;
377*7a7741afSMartin Matuska 	abd_verify(abd);
378*7a7741afSMartin Matuska 	ASSERT3U(abd->abd_size, >=, 0);
379*7a7741afSMartin Matuska 	if (abd_is_linear(abd)) {
380*7a7741afSMartin Matuska 		buf = abd_to_buf(abd);
381*7a7741afSMartin Matuska 	} else {
382*7a7741afSMartin Matuska 		buf = zio_buf_alloc(n);
383*7a7741afSMartin Matuska 	}
384*7a7741afSMartin Matuska #ifdef ZFS_DEBUG
385*7a7741afSMartin Matuska 	(void) zfs_refcount_add_many(&abd->abd_children, n, buf);
386*7a7741afSMartin Matuska #endif
387*7a7741afSMartin Matuska 	return (buf);
388*7a7741afSMartin Matuska }
389*7a7741afSMartin Matuska 
390*7a7741afSMartin Matuska void *
391*7a7741afSMartin Matuska abd_borrow_buf_copy(abd_t *abd, size_t n)
392*7a7741afSMartin Matuska {
393*7a7741afSMartin Matuska 	void *buf = abd_borrow_buf(abd, n);
394*7a7741afSMartin Matuska 	if (!abd_is_linear(abd)) {
395*7a7741afSMartin Matuska 		abd_copy_to_buf(buf, abd, n);
396*7a7741afSMartin Matuska 	}
397*7a7741afSMartin Matuska 	return (buf);
398*7a7741afSMartin Matuska }
399*7a7741afSMartin Matuska 
400*7a7741afSMartin Matuska /*
401*7a7741afSMartin Matuska  * Return a borrowed raw buffer to an ABD. If the ABD is scattered, this will
402*7a7741afSMartin Matuska  * no change the contents of the ABD and will ASSERT that you didn't modify
403*7a7741afSMartin Matuska  * the buffer since it was borrowed. If you want any changes you made to buf to
404*7a7741afSMartin Matuska  * be copied back to abd, use abd_return_buf_copy() instead.
405*7a7741afSMartin Matuska  */
406*7a7741afSMartin Matuska void
407*7a7741afSMartin Matuska abd_return_buf(abd_t *abd, void *buf, size_t n)
408*7a7741afSMartin Matuska {
409*7a7741afSMartin Matuska 	abd_verify(abd);
410*7a7741afSMartin Matuska 	ASSERT3U(abd->abd_size, >=, n);
411*7a7741afSMartin Matuska #ifdef ZFS_DEBUG
412*7a7741afSMartin Matuska 	(void) zfs_refcount_remove_many(&abd->abd_children, n, buf);
413*7a7741afSMartin Matuska #endif
414*7a7741afSMartin Matuska 	if (abd_is_linear(abd)) {
415*7a7741afSMartin Matuska 		ASSERT3P(buf, ==, abd_to_buf(abd));
416*7a7741afSMartin Matuska 	} else {
417*7a7741afSMartin Matuska 		ASSERT0(abd_cmp_buf(abd, buf, n));
418*7a7741afSMartin Matuska 		zio_buf_free(buf, n);
419*7a7741afSMartin Matuska 	}
420*7a7741afSMartin Matuska }
421*7a7741afSMartin Matuska 
422*7a7741afSMartin Matuska void
423*7a7741afSMartin Matuska abd_return_buf_copy(abd_t *abd, void *buf, size_t n)
424*7a7741afSMartin Matuska {
425*7a7741afSMartin Matuska 	if (!abd_is_linear(abd)) {
426*7a7741afSMartin Matuska 		abd_copy_from_buf(abd, buf, n);
427*7a7741afSMartin Matuska 	}
428*7a7741afSMartin Matuska 	abd_return_buf(abd, buf, n);
429*7a7741afSMartin Matuska }
430