xref: /freebsd-src/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c (revision c14e17a49cdd72c8c05d12fbec631c409b14b9cb)
1 /*
2  * Copyright (c) 2020 iXsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/dmu.h>
32 #include <sys/dmu_impl.h>
33 #include <sys/dmu_recv.h>
34 #include <sys/dmu_tx.h>
35 #include <sys/dbuf.h>
36 #include <sys/dnode.h>
37 #include <sys/zfs_context.h>
38 #include <sys/dmu_objset.h>
39 #include <sys/dmu_traverse.h>
40 #include <sys/dsl_dataset.h>
41 #include <sys/dsl_dir.h>
42 #include <sys/dsl_pool.h>
43 #include <sys/dsl_synctask.h>
44 #include <sys/zfs_ioctl.h>
45 #include <sys/zap.h>
46 #include <sys/zio_checksum.h>
47 #include <sys/zfs_znode.h>
48 #include <sys/zfs_file.h>
49 #include <sys/buf.h>
50 #include <sys/stat.h>
51 
52 int
53 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
54 {
55 	struct thread *td;
56 	int rc, fd;
57 
58 	td = curthread;
59 	pwd_ensure_dirs();
60 	/* 12.x doesn't take a const char * */
61 	rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
62 	    UIO_SYSSPACE, flags, mode);
63 	if (rc)
64 		return (SET_ERROR(rc));
65 	fd = td->td_retval[0];
66 	td->td_retval[0] = 0;
67 	if (fget(curthread, fd, &cap_no_rights, fpp))
68 		kern_close(td, fd);
69 	return (0);
70 }
71 
72 void
73 zfs_file_close(zfs_file_t *fp)
74 {
75 	fo_close(fp, curthread);
76 }
77 
78 static int
79 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp,
80     ssize_t *resid)
81 {
82 	ssize_t rc;
83 	struct uio auio;
84 	struct thread *td;
85 	struct iovec aiov;
86 
87 	td = curthread;
88 	aiov.iov_base = (void *)(uintptr_t)buf;
89 	aiov.iov_len = count;
90 	auio.uio_iov = &aiov;
91 	auio.uio_iovcnt = 1;
92 	auio.uio_segflg = UIO_SYSSPACE;
93 	auio.uio_resid = count;
94 	auio.uio_rw = UIO_WRITE;
95 	auio.uio_td = td;
96 	auio.uio_offset = *offp;
97 
98 	if ((fp->f_flag & FWRITE) == 0)
99 		return (SET_ERROR(EBADF));
100 
101 	if (fp->f_type == DTYPE_VNODE)
102 		bwillwrite();
103 
104 	rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td);
105 	if (rc)
106 		return (SET_ERROR(rc));
107 	if (resid)
108 		*resid = auio.uio_resid;
109 	else if (auio.uio_resid)
110 		return (SET_ERROR(EIO));
111 	*offp += count - auio.uio_resid;
112 	return (rc);
113 }
114 
115 int
116 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
117 {
118 	loff_t off = fp->f_offset;
119 	ssize_t rc;
120 
121 	rc = zfs_file_write_impl(fp, buf, count, &off, resid);
122 	if (rc == 0)
123 		fp->f_offset = off;
124 
125 	return (SET_ERROR(rc));
126 }
127 
128 int
129 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
130     ssize_t *resid)
131 {
132 	return (zfs_file_write_impl(fp, buf, count, &off, resid));
133 }
134 
135 static int
136 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp,
137     ssize_t *resid)
138 {
139 	ssize_t rc;
140 	struct uio auio;
141 	struct thread *td;
142 	struct iovec aiov;
143 
144 	td = curthread;
145 	aiov.iov_base = (void *)(uintptr_t)buf;
146 	aiov.iov_len = count;
147 	auio.uio_iov = &aiov;
148 	auio.uio_iovcnt = 1;
149 	auio.uio_segflg = UIO_SYSSPACE;
150 	auio.uio_resid = count;
151 	auio.uio_rw = UIO_READ;
152 	auio.uio_td = td;
153 	auio.uio_offset = *offp;
154 
155 	if ((fp->f_flag & FREAD) == 0)
156 		return (SET_ERROR(EBADF));
157 
158 	rc = fo_read(fp, &auio, td->td_ucred, FOF_OFFSET, td);
159 	if (rc)
160 		return (SET_ERROR(rc));
161 	if (resid)
162 		*resid = auio.uio_resid;
163 	*offp += count - auio.uio_resid;
164 	return (SET_ERROR(0));
165 }
166 
167 int
168 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid)
169 {
170 	loff_t off = fp->f_offset;
171 	ssize_t rc;
172 
173 	rc = zfs_file_read_impl(fp, buf, count, &off, resid);
174 	if (rc == 0)
175 		fp->f_offset = off;
176 	return (rc);
177 }
178 
179 int
180 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off,
181     ssize_t *resid)
182 {
183 	return (zfs_file_read_impl(fp, buf, count, &off, resid));
184 }
185 
186 int
187 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence)
188 {
189 	int rc;
190 	struct thread *td;
191 
192 	td = curthread;
193 	if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
194 		return (SET_ERROR(ESPIPE));
195 	rc = fo_seek(fp, *offp, whence, td);
196 	if (rc == 0)
197 		*offp = td->td_uretoff.tdu_off;
198 	return (SET_ERROR(rc));
199 }
200 
201 int
202 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr)
203 {
204 	struct thread *td;
205 	struct stat sb;
206 	int rc;
207 
208 	td = curthread;
209 
210 	rc = fo_stat(fp, &sb, td->td_ucred, td);
211 	if (rc)
212 		return (SET_ERROR(rc));
213 	zfattr->zfa_size = sb.st_size;
214 	zfattr->zfa_mode = sb.st_mode;
215 
216 	return (0);
217 }
218 
219 static __inline int
220 zfs_vop_fsync(vnode_t *vp)
221 {
222 	struct mount *mp;
223 	int error;
224 
225 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
226 		goto drop;
227 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
228 	error = VOP_FSYNC(vp, MNT_WAIT, curthread);
229 	VOP_UNLOCK1(vp);
230 	vn_finished_write(mp);
231 drop:
232 	return (SET_ERROR(error));
233 }
234 
235 int
236 zfs_file_fsync(zfs_file_t *fp, int flags)
237 {
238 	if (fp->f_type != DTYPE_VNODE)
239 		return (EINVAL);
240 
241 	return (zfs_vop_fsync(fp->f_vnode));
242 }
243 
244 int
245 zfs_file_get(int fd, zfs_file_t **fpp)
246 {
247 	struct file *fp;
248 
249 	if (fget(curthread, fd, &cap_no_rights, &fp))
250 		return (SET_ERROR(EBADF));
251 
252 	*fpp = fp;
253 	return (0);
254 }
255 
256 void
257 zfs_file_put(int fd)
258 {
259 	struct file *fp;
260 
261 	/* No CAP_ rights required, as we're only releasing. */
262 	if (fget(curthread, fd, &cap_no_rights, &fp) == 0) {
263 		fdrop(fp, curthread);
264 		fdrop(fp, curthread);
265 	}
266 }
267 
268 loff_t
269 zfs_file_off(zfs_file_t *fp)
270 {
271 	return (fp->f_offset);
272 }
273 
274 void *
275 zfs_file_private(zfs_file_t *fp)
276 {
277 	file_t *tmpfp;
278 	void *data;
279 	int error;
280 
281 	tmpfp = curthread->td_fpop;
282 	curthread->td_fpop = fp;
283 	error = devfs_get_cdevpriv(&data);
284 	curthread->td_fpop = tmpfp;
285 	if (error != 0)
286 		return (NULL);
287 	return (data);
288 }
289 
290 int
291 zfs_file_unlink(const char *fnamep)
292 {
293 	enum uio_seg seg = UIO_SYSSPACE;
294 	int rc;
295 
296 #if __FreeBSD_version >= 1300018
297 	rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0);
298 #else
299 #ifdef AT_BENEATH
300 	rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
301 	    seg, 0, 0);
302 #else
303 	rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
304 	    seg, 0);
305 #endif
306 #endif
307 	return (SET_ERROR(rc));
308 }
309