xref: /freebsd/sys/contrib/openzfs/module/os/linux/zfs/zfs_uio.c (revision 5def4c47d4bd90b209b9b4a4ba9faec15846d8fd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved	*/
28 
29 /*
30  * University Copyright- Copyright (c) 1982, 1986, 1988
31  * The Regents of the University of California
32  * All Rights Reserved
33  *
34  * University Acknowledgment- Portions of this document are derived from
35  * software developed by the University of California, Berkeley, and its
36  * contributors.
37  */
38 /*
39  * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
40  */
41 
42 #ifdef _KERNEL
43 
44 #include <sys/types.h>
45 #include <sys/uio_impl.h>
46 #include <sys/sysmacros.h>
47 #include <sys/strings.h>
48 #include <linux/kmap_compat.h>
49 #include <linux/uaccess.h>
50 
51 /*
52  * Move "n" bytes at byte address "p"; "rw" indicates the direction
53  * of the move, and the I/O parameters are provided in "uio", which is
54  * update to reflect the data which was moved.  Returns 0 on success or
55  * a non-zero errno on failure.
56  */
57 static int
58 zfs_uiomove_iov(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio)
59 {
60 	const struct iovec *iov = uio->uio_iov;
61 	size_t skip = uio->uio_skip;
62 	ulong_t cnt;
63 
64 	while (n && uio->uio_resid) {
65 		cnt = MIN(iov->iov_len - skip, n);
66 		switch (uio->uio_segflg) {
67 		case UIO_USERSPACE:
68 			/*
69 			 * p = kernel data pointer
70 			 * iov->iov_base = user data pointer
71 			 */
72 			if (rw == UIO_READ) {
73 				if (copy_to_user(iov->iov_base+skip, p, cnt))
74 					return (EFAULT);
75 			} else {
76 				unsigned long b_left = 0;
77 				if (uio->uio_fault_disable) {
78 					if (!zfs_access_ok(VERIFY_READ,
79 					    (iov->iov_base + skip), cnt)) {
80 						return (EFAULT);
81 					}
82 					pagefault_disable();
83 					b_left =
84 					    __copy_from_user_inatomic(p,
85 					    (iov->iov_base + skip), cnt);
86 					pagefault_enable();
87 				} else {
88 					b_left =
89 					    copy_from_user(p,
90 					    (iov->iov_base + skip), cnt);
91 				}
92 				if (b_left > 0) {
93 					unsigned long c_bytes =
94 					    cnt - b_left;
95 					uio->uio_skip += c_bytes;
96 					ASSERT3U(uio->uio_skip, <,
97 					    iov->iov_len);
98 					uio->uio_resid -= c_bytes;
99 					uio->uio_loffset += c_bytes;
100 					return (EFAULT);
101 				}
102 			}
103 			break;
104 		case UIO_SYSSPACE:
105 			if (rw == UIO_READ)
106 				bcopy(p, iov->iov_base + skip, cnt);
107 			else
108 				bcopy(iov->iov_base + skip, p, cnt);
109 			break;
110 		default:
111 			ASSERT(0);
112 		}
113 		skip += cnt;
114 		if (skip == iov->iov_len) {
115 			skip = 0;
116 			uio->uio_iov = (++iov);
117 			uio->uio_iovcnt--;
118 		}
119 		uio->uio_skip = skip;
120 		uio->uio_resid -= cnt;
121 		uio->uio_loffset += cnt;
122 		p = (caddr_t)p + cnt;
123 		n -= cnt;
124 	}
125 	return (0);
126 }
127 
128 static int
129 zfs_uiomove_bvec(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio)
130 {
131 	const struct bio_vec *bv = uio->uio_bvec;
132 	size_t skip = uio->uio_skip;
133 	ulong_t cnt;
134 
135 	while (n && uio->uio_resid) {
136 		void *paddr;
137 		cnt = MIN(bv->bv_len - skip, n);
138 
139 		paddr = zfs_kmap_atomic(bv->bv_page);
140 		if (rw == UIO_READ)
141 			bcopy(p, paddr + bv->bv_offset + skip, cnt);
142 		else
143 			bcopy(paddr + bv->bv_offset + skip, p, cnt);
144 		zfs_kunmap_atomic(paddr);
145 
146 		skip += cnt;
147 		if (skip == bv->bv_len) {
148 			skip = 0;
149 			uio->uio_bvec = (++bv);
150 			uio->uio_iovcnt--;
151 		}
152 		uio->uio_skip = skip;
153 		uio->uio_resid -= cnt;
154 		uio->uio_loffset += cnt;
155 		p = (caddr_t)p + cnt;
156 		n -= cnt;
157 	}
158 	return (0);
159 }
160 
161 #if defined(HAVE_VFS_IOV_ITER)
162 static int
163 zfs_uiomove_iter(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio,
164     boolean_t revert)
165 {
166 	size_t cnt = MIN(n, uio->uio_resid);
167 
168 	if (uio->uio_skip)
169 		iov_iter_advance(uio->uio_iter, uio->uio_skip);
170 
171 	if (rw == UIO_READ)
172 		cnt = copy_to_iter(p, cnt, uio->uio_iter);
173 	else
174 		cnt = copy_from_iter(p, cnt, uio->uio_iter);
175 
176 	/*
177 	 * When operating on a full pipe no bytes are processed.
178 	 * In which case return EFAULT which is converted to EAGAIN
179 	 * by the kernel's generic_file_splice_read() function.
180 	 */
181 	if (cnt == 0)
182 		return (EFAULT);
183 
184 	/*
185 	 * Revert advancing the uio_iter.  This is set by zfs_uiocopy()
186 	 * to avoid consuming the uio and its iov_iter structure.
187 	 */
188 	if (revert)
189 		iov_iter_revert(uio->uio_iter, cnt);
190 
191 	uio->uio_resid -= cnt;
192 	uio->uio_loffset += cnt;
193 
194 	return (0);
195 }
196 #endif
197 
198 int
199 zfs_uiomove(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio)
200 {
201 	if (uio->uio_segflg == UIO_BVEC)
202 		return (zfs_uiomove_bvec(p, n, rw, uio));
203 #if defined(HAVE_VFS_IOV_ITER)
204 	else if (uio->uio_segflg == UIO_ITER)
205 		return (zfs_uiomove_iter(p, n, rw, uio, B_FALSE));
206 #endif
207 	else
208 		return (zfs_uiomove_iov(p, n, rw, uio));
209 }
210 EXPORT_SYMBOL(zfs_uiomove);
211 
212 /*
213  * Fault in the pages of the first n bytes specified by the uio structure.
214  * 1 byte in each page is touched and the uio struct is unmodified. Any
215  * error will terminate the process as this is only a best attempt to get
216  * the pages resident.
217  */
218 int
219 zfs_uio_prefaultpages(ssize_t n, zfs_uio_t *uio)
220 {
221 	if (uio->uio_segflg == UIO_SYSSPACE || uio->uio_segflg == UIO_BVEC) {
222 		/* There's never a need to fault in kernel pages */
223 		return (0);
224 #if defined(HAVE_VFS_IOV_ITER)
225 	} else if (uio->uio_segflg == UIO_ITER) {
226 		/*
227 		 * At least a Linux 4.9 kernel, iov_iter_fault_in_readable()
228 		 * can be relied on to fault in user pages when referenced.
229 		 */
230 		if (iov_iter_fault_in_readable(uio->uio_iter, n))
231 			return (EFAULT);
232 #endif
233 	} else {
234 		/* Fault in all user pages */
235 		ASSERT3S(uio->uio_segflg, ==, UIO_USERSPACE);
236 		const struct iovec *iov = uio->uio_iov;
237 		int iovcnt = uio->uio_iovcnt;
238 		size_t skip = uio->uio_skip;
239 		uint8_t tmp;
240 		caddr_t p;
241 
242 		for (; n > 0 && iovcnt > 0; iov++, iovcnt--, skip = 0) {
243 			ulong_t cnt = MIN(iov->iov_len - skip, n);
244 			/* empty iov */
245 			if (cnt == 0)
246 				continue;
247 			n -= cnt;
248 			/* touch each page in this segment. */
249 			p = iov->iov_base + skip;
250 			while (cnt) {
251 				if (get_user(tmp, (uint8_t *)p))
252 					return (EFAULT);
253 				ulong_t incr = MIN(cnt, PAGESIZE);
254 				p += incr;
255 				cnt -= incr;
256 			}
257 			/* touch the last byte in case it straddles a page. */
258 			p--;
259 			if (get_user(tmp, (uint8_t *)p))
260 				return (EFAULT);
261 		}
262 	}
263 
264 	return (0);
265 }
266 EXPORT_SYMBOL(zfs_uio_prefaultpages);
267 
268 /*
269  * The same as zfs_uiomove() but doesn't modify uio structure.
270  * return in cbytes how many bytes were copied.
271  */
272 int
273 zfs_uiocopy(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio, size_t *cbytes)
274 {
275 	zfs_uio_t uio_copy;
276 	int ret;
277 
278 	bcopy(uio, &uio_copy, sizeof (zfs_uio_t));
279 
280 	if (uio->uio_segflg == UIO_BVEC)
281 		ret = zfs_uiomove_bvec(p, n, rw, &uio_copy);
282 #if defined(HAVE_VFS_IOV_ITER)
283 	else if (uio->uio_segflg == UIO_ITER)
284 		ret = zfs_uiomove_iter(p, n, rw, &uio_copy, B_TRUE);
285 #endif
286 	else
287 		ret = zfs_uiomove_iov(p, n, rw, &uio_copy);
288 
289 	*cbytes = uio->uio_resid - uio_copy.uio_resid;
290 
291 	return (ret);
292 }
293 EXPORT_SYMBOL(zfs_uiocopy);
294 
295 /*
296  * Drop the next n chars out of *uio.
297  */
298 void
299 zfs_uioskip(zfs_uio_t *uio, size_t n)
300 {
301 	if (n > uio->uio_resid)
302 		return;
303 
304 	if (uio->uio_segflg == UIO_BVEC) {
305 		uio->uio_skip += n;
306 		while (uio->uio_iovcnt &&
307 		    uio->uio_skip >= uio->uio_bvec->bv_len) {
308 			uio->uio_skip -= uio->uio_bvec->bv_len;
309 			uio->uio_bvec++;
310 			uio->uio_iovcnt--;
311 		}
312 #if defined(HAVE_VFS_IOV_ITER)
313 	} else if (uio->uio_segflg == UIO_ITER) {
314 		iov_iter_advance(uio->uio_iter, n);
315 #endif
316 	} else {
317 		uio->uio_skip += n;
318 		while (uio->uio_iovcnt &&
319 		    uio->uio_skip >= uio->uio_iov->iov_len) {
320 			uio->uio_skip -= uio->uio_iov->iov_len;
321 			uio->uio_iov++;
322 			uio->uio_iovcnt--;
323 		}
324 	}
325 	uio->uio_loffset += n;
326 	uio->uio_resid -= n;
327 }
328 EXPORT_SYMBOL(zfs_uioskip);
329 
330 #endif /* _KERNEL */
331