1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
4 * Copyright (C) 2007 The Regents of the University of California.
5 * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
6 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
8 * UCRL-CODE-235197
9 *
10 * This file is part of the SPL, Solaris Porting Layer.
11 *
12 * The SPL is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 * The SPL is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #ifndef _SPL_UIO_H
27 #define _SPL_UIO_H
28
29 #include <sys/debug.h>
30 #include <linux/uio.h>
31 #include <linux/blkdev.h>
32 #include <linux/blkdev_compat.h>
33 #include <linux/mm.h>
34 #include <linux/bio.h>
35 #include <asm/uaccess.h>
36 #include <sys/types.h>
37 #include <sys/string.h>
38
39 /*
40 * uio_extflg: extended flags
41 */
42 #define UIO_DIRECT 0x0001 /* Direct I/O request */
43
44 #if defined(HAVE_FAULT_IN_IOV_ITER_READABLE)
45 #define iov_iter_fault_in_readable(a, b) fault_in_iov_iter_readable(a, b)
46 #endif
47
48 typedef struct iovec iovec_t;
49
50 typedef enum zfs_uio_rw {
51 UIO_READ = 0,
52 UIO_WRITE = 1,
53 } zfs_uio_rw_t;
54
55 typedef enum zfs_uio_seg {
56 UIO_SYSSPACE = 0,
57 UIO_BVEC = 1,
58 UIO_ITER = 2,
59 } zfs_uio_seg_t;
60
61 /*
62 * This structures is used when doing Direct I/O.
63 */
64 typedef struct {
65 struct page **pages; /* Mapped pages */
66 long npages; /* Number of mapped pages */
67 boolean_t pinned; /* Whether FOLL_PIN was used */
68 } zfs_uio_dio_t;
69
70 typedef struct zfs_uio {
71 union {
72 const struct iovec *uio_iov;
73 const struct bio_vec *uio_bvec;
74 struct iov_iter *uio_iter;
75 };
76 int uio_iovcnt; /* Number of iovecs */
77 offset_t uio_soffset; /* Starting logical offset */
78 offset_t uio_loffset; /* Current logical offset */
79 zfs_uio_seg_t uio_segflg; /* Segment type */
80 boolean_t uio_fault_disable;
81 uint16_t uio_fmode; /* Access mode (unused) */
82 uint16_t uio_extflg; /* Extra flags (UIO_DIRECT) */
83 ssize_t uio_resid; /* Residual unprocessed bytes */
84 size_t uio_skip; /* Skipped bytes in current iovec */
85 zfs_uio_dio_t uio_dio; /* Direct I/O user pages */
86
87 struct request *rq;
88 } zfs_uio_t;
89
90
91 #define zfs_uio_segflg(u) (u)->uio_segflg
92 #define zfs_uio_offset(u) (u)->uio_loffset
93 #define zfs_uio_resid(u) (u)->uio_resid
94 #define zfs_uio_iovcnt(u) (u)->uio_iovcnt
95 #define zfs_uio_iovlen(u, idx) (u)->uio_iov[(idx)].iov_len
96 #define zfs_uio_iovbase(u, idx) (u)->uio_iov[(idx)].iov_base
97 #define zfs_uio_fault_disable(u, set) (u)->uio_fault_disable = set
98 #define zfs_uio_soffset(u) (u)->uio_soffset
99 #define zfs_uio_rlimit_fsize(z, u) (0)
100 #define zfs_uio_fault_move(p, n, rw, u) zfs_uiomove((p), (n), (rw), (u))
101
102 extern int zfs_uio_prefaultpages(ssize_t, zfs_uio_t *);
103
104 static inline void
zfs_uio_setoffset(zfs_uio_t * uio,offset_t off)105 zfs_uio_setoffset(zfs_uio_t *uio, offset_t off)
106 {
107 uio->uio_loffset = off;
108 }
109
110 static inline void
zfs_uio_setsoffset(zfs_uio_t * uio,offset_t off)111 zfs_uio_setsoffset(zfs_uio_t *uio, offset_t off)
112 {
113 ASSERT3U(zfs_uio_offset(uio), ==, off);
114 zfs_uio_soffset(uio) = off;
115 }
116
117 static inline void
zfs_uio_advance(zfs_uio_t * uio,ssize_t size)118 zfs_uio_advance(zfs_uio_t *uio, ssize_t size)
119 {
120 uio->uio_resid -= size;
121 uio->uio_loffset += size;
122 }
123
124 static inline void
zfs_uio_iovec_init(zfs_uio_t * uio,const struct iovec * iov,unsigned long nr_segs,offset_t offset,zfs_uio_seg_t seg,ssize_t resid,size_t skip)125 zfs_uio_iovec_init(zfs_uio_t *uio, const struct iovec *iov,
126 unsigned long nr_segs, offset_t offset, zfs_uio_seg_t seg, ssize_t resid,
127 size_t skip)
128 {
129 ASSERT(seg == UIO_SYSSPACE);
130
131 uio->uio_iov = iov;
132 uio->uio_iovcnt = nr_segs;
133 uio->uio_loffset = offset;
134 uio->uio_segflg = seg;
135 uio->uio_fault_disable = B_FALSE;
136 uio->uio_fmode = 0;
137 uio->uio_extflg = 0;
138 uio->uio_resid = resid;
139 uio->uio_skip = skip;
140 uio->uio_soffset = uio->uio_loffset;
141 memset(&uio->uio_dio, 0, sizeof (zfs_uio_dio_t));
142 }
143
144 static inline void
zfs_uio_bvec_init(zfs_uio_t * uio,struct bio * bio,struct request * rq)145 zfs_uio_bvec_init(zfs_uio_t *uio, struct bio *bio, struct request *rq)
146 {
147 /* Either bio or rq will be set, but not both */
148 ASSERT3P(uio, !=, bio);
149
150 if (bio) {
151 uio->uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio);
152 uio->uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)];
153 } else {
154 uio->uio_bvec = NULL;
155 uio->uio_iovcnt = 0;
156 }
157
158 uio->uio_loffset = io_offset(bio, rq);
159 uio->uio_segflg = UIO_BVEC;
160 uio->uio_fault_disable = B_FALSE;
161 uio->uio_fmode = 0;
162 uio->uio_extflg = 0;
163 uio->uio_resid = io_size(bio, rq);
164 if (bio) {
165 uio->uio_skip = BIO_BI_SKIP(bio);
166 } else {
167 uio->uio_skip = 0;
168 }
169
170 uio->rq = rq;
171 uio->uio_soffset = uio->uio_loffset;
172 memset(&uio->uio_dio, 0, sizeof (zfs_uio_dio_t));
173 }
174
175 static inline void
zfs_uio_iov_iter_init(zfs_uio_t * uio,struct iov_iter * iter,offset_t offset,ssize_t resid,size_t skip)176 zfs_uio_iov_iter_init(zfs_uio_t *uio, struct iov_iter *iter, offset_t offset,
177 ssize_t resid, size_t skip)
178 {
179 uio->uio_iter = iter;
180 uio->uio_iovcnt = iter->nr_segs;
181 uio->uio_loffset = offset;
182 uio->uio_segflg = UIO_ITER;
183 uio->uio_fault_disable = B_FALSE;
184 uio->uio_fmode = 0;
185 uio->uio_extflg = 0;
186 uio->uio_resid = resid;
187 uio->uio_skip = skip;
188 uio->uio_soffset = uio->uio_loffset;
189 memset(&uio->uio_dio, 0, sizeof (zfs_uio_dio_t));
190 }
191
192 #if defined(HAVE_ITER_IOV)
193 #define zfs_uio_iter_iov(iter) iter_iov((iter))
194 #else
195 #define zfs_uio_iter_iov(iter) (iter)->iov
196 #endif
197
198 #if defined(HAVE_IOV_ITER_TYPE)
199 #define zfs_uio_iov_iter_type(iter) iov_iter_type((iter))
200 #else
201 #define zfs_uio_iov_iter_type(iter) (iter)->type
202 #endif
203
204 #if defined(HAVE_ITER_IS_UBUF)
205 #define zfs_user_backed_iov_iter(iter) \
206 (iter_is_ubuf((iter)) || \
207 (zfs_uio_iov_iter_type((iter)) == ITER_IOVEC))
208 #else
209 #define zfs_user_backed_iov_iter(iter) \
210 (zfs_uio_iov_iter_type((iter)) == ITER_IOVEC)
211 #endif
212
213 #endif /* SPL_UIO_H */
214