]>
git.proxmox.com Git - mirror_zfs-debian.git/blob - module/zcommon/zfs_uio.c
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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
43 * The uio support from OpenSolaris has been added as a short term
44 * work around. The hope is to adopt native Linux type and drop the
45 * use of uio's entirely. Under Linux they only add overhead and
46 * when possible we want to use native APIs for the ZPL layer.
50 #include <sys/types.h>
51 #include <sys/uio_impl.h>
52 #include <linux/kmap_compat.h>
55 * Move "n" bytes at byte address "p"; "rw" indicates the direction
56 * of the move, and the I/O parameters are provided in "uio", which is
57 * update to reflect the data which was moved. Returns 0 on success or
58 * a non-zero errno on failure.
61 uiomove_iov(void *p
, size_t n
, enum uio_rw rw
, struct uio
*uio
)
63 const struct iovec
*iov
= uio
->uio_iov
;
64 size_t skip
= uio
->uio_skip
;
67 while (n
&& uio
->uio_resid
) {
68 cnt
= MIN(iov
->iov_len
- skip
, n
);
69 switch (uio
->uio_segflg
) {
73 * p = kernel data pointer
74 * iov->iov_base = user data pointer
77 if (copy_to_user(iov
->iov_base
+skip
, p
, cnt
))
80 if (copy_from_user(p
, iov
->iov_base
+skip
, cnt
))
86 bcopy(p
, iov
->iov_base
+ skip
, cnt
);
88 bcopy(iov
->iov_base
+ skip
, p
, cnt
);
94 if (skip
== iov
->iov_len
) {
96 uio
->uio_iov
= (++iov
);
100 uio
->uio_resid
-= cnt
;
101 uio
->uio_loffset
+= cnt
;
102 p
= (caddr_t
)p
+ cnt
;
109 uiomove_bvec(void *p
, size_t n
, enum uio_rw rw
, struct uio
*uio
)
111 const struct bio_vec
*bv
= uio
->uio_bvec
;
112 size_t skip
= uio
->uio_skip
;
115 while (n
&& uio
->uio_resid
) {
117 cnt
= MIN(bv
->bv_len
- skip
, n
);
119 paddr
= zfs_kmap_atomic(bv
->bv_page
, KM_USER1
);
121 bcopy(p
, paddr
+ bv
->bv_offset
+ skip
, cnt
);
123 bcopy(paddr
+ bv
->bv_offset
+ skip
, p
, cnt
);
124 zfs_kunmap_atomic(paddr
, KM_USER1
);
127 if (skip
== bv
->bv_len
) {
129 uio
->uio_bvec
= (++bv
);
132 uio
->uio_skip
= skip
;
133 uio
->uio_resid
-= cnt
;
134 uio
->uio_loffset
+= cnt
;
135 p
= (caddr_t
)p
+ cnt
;
142 uiomove(void *p
, size_t n
, enum uio_rw rw
, struct uio
*uio
)
144 if (uio
->uio_segflg
!= UIO_BVEC
)
145 return (uiomove_iov(p
, n
, rw
, uio
));
147 return (uiomove_bvec(p
, n
, rw
, uio
));
149 EXPORT_SYMBOL(uiomove
);
151 #define fuword8(uptr, vptr) get_user((*vptr), (uptr))
154 * Fault in the pages of the first n bytes specified by the uio structure.
155 * 1 byte in each page is touched and the uio struct is unmodified. Any
156 * error will terminate the process as this is only a best attempt to get
157 * the pages resident.
160 uio_prefaultpages(ssize_t n
, struct uio
*uio
)
162 const struct iovec
*iov
;
169 /* no need to fault in kernel pages */
170 switch (uio
->uio_segflg
) {
182 iovcnt
= uio
->uio_iovcnt
;
183 skip
= uio
->uio_skip
;
185 for (; n
> 0 && iovcnt
> 0; iov
++, iovcnt
--, skip
= 0) {
186 cnt
= MIN(iov
->iov_len
- skip
, n
);
192 * touch each page in this segment.
194 p
= iov
->iov_base
+ skip
;
196 if (fuword8((uint8_t *)p
, &tmp
))
198 incr
= MIN(cnt
, PAGESIZE
);
203 * touch the last byte in case it straddles a page.
206 if (fuword8((uint8_t *)p
, &tmp
))
210 EXPORT_SYMBOL(uio_prefaultpages
);
213 * same as uiomove() but doesn't modify uio structure.
214 * return in cbytes how many bytes were copied.
217 uiocopy(void *p
, size_t n
, enum uio_rw rw
, struct uio
*uio
, size_t *cbytes
)
222 bcopy(uio
, &uio_copy
, sizeof (struct uio
));
223 ret
= uiomove(p
, n
, rw
, &uio_copy
);
224 *cbytes
= uio
->uio_resid
- uio_copy
.uio_resid
;
227 EXPORT_SYMBOL(uiocopy
);
230 * Drop the next n chars out of *uiop.
233 uioskip(uio_t
*uiop
, size_t n
)
235 if (n
> uiop
->uio_resid
)
239 if (uiop
->uio_segflg
!= UIO_BVEC
) {
240 while (uiop
->uio_iovcnt
&&
241 uiop
->uio_skip
>= uiop
->uio_iov
->iov_len
) {
242 uiop
->uio_skip
-= uiop
->uio_iov
->iov_len
;
247 while (uiop
->uio_iovcnt
&&
248 uiop
->uio_skip
>= uiop
->uio_bvec
->bv_len
) {
249 uiop
->uio_skip
-= uiop
->uio_bvec
->bv_len
;
254 uiop
->uio_loffset
+= n
;
255 uiop
->uio_resid
-= n
;
257 EXPORT_SYMBOL(uioskip
);