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/dmu.h>
29 #include <sys/dmu_impl.h>
30 #include <sys/dmu_recv.h>
31 #include <sys/dmu_tx.h>
32 #include <sys/dbuf.h>
33 #include <sys/dnode.h>
34 #include <sys/zfs_context.h>
35 #include <sys/dmu_objset.h>
36 #include <sys/dmu_traverse.h>
37 #include <sys/dsl_dataset.h>
38 #include <sys/dsl_dir.h>
39 #include <sys/dsl_pool.h>
40 #include <sys/dsl_synctask.h>
41 #include <sys/zfs_ioctl.h>
42 #include <sys/zap.h>
43 #include <sys/zio_checksum.h>
44 #include <sys/zfs_znode.h>
45 #include <sys/zfs_file.h>
46 #include <sys/buf.h>
47 #include <sys/stat.h>
48 
49 int
50 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
51 {
52 	struct thread *td;
53 	int rc, fd;
54 
55 	td = curthread;
56 	pwd_ensure_dirs();
57 	/* 12.x doesn't take a const char * */
58 	rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
59 	    UIO_SYSSPACE, flags, mode);
60 	if (rc)
61 		return (SET_ERROR(rc));
62 	fd = td->td_retval[0];
63 	td->td_retval[0] = 0;
64 	if (fget(curthread, fd, &cap_no_rights, fpp))
65 		kern_close(td, fd);
66 	return (0);
67 }
68 
69 void
70 zfs_file_close(zfs_file_t *fp)
71 {
72 	fo_close(fp, curthread);
73 }
74 
75 static int
76 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp,
77     ssize_t *resid)
78 {
79 	ssize_t rc;
80 	struct uio auio;
81 	struct thread *td;
82 	struct iovec aiov;
83 
84 	td = curthread;
85 	aiov.iov_base = (void *)(uintptr_t)buf;
86 	aiov.iov_len = count;
87 	auio.uio_iov = &aiov;
88 	auio.uio_iovcnt = 1;
89 	auio.uio_segflg = UIO_SYSSPACE;
90 	auio.uio_resid = count;
91 	auio.uio_rw = UIO_WRITE;
92 	auio.uio_td = td;
93 	auio.uio_offset = *offp;
94 
95 	if ((fp->f_flag & FWRITE) == 0)
96 		return (SET_ERROR(EBADF));
97 
98 	if (fp->f_type == DTYPE_VNODE)
99 		bwillwrite();
100 
101 	rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td);
102 	if (rc)
103 		return (SET_ERROR(rc));
104 	if (resid)
105 		*resid = auio.uio_resid;
106 	else if (auio.uio_resid)
107 		return (SET_ERROR(EIO));
108 	*offp += count - auio.uio_resid;
109 	return (rc);
110 }
111 
112 int
113 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
114 {
115 	loff_t off = fp->f_offset;
116 	ssize_t rc;
117 
118 	rc = zfs_file_write_impl(fp, buf, count, &off, resid);
119 	if (rc == 0)
120 		fp->f_offset = off;
121 
122 	return (SET_ERROR(rc));
123 }
124 
125 int
126 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
127     ssize_t *resid)
128 {
129 	return (zfs_file_write_impl(fp, buf, count, &off, resid));
130 }
131 
132 static int
133 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp,
134     ssize_t *resid)
135 {
136 	ssize_t rc;
137 	struct uio auio;
138 	struct thread *td;
139 	struct iovec aiov;
140 
141 	td = curthread;
142 	aiov.iov_base = (void *)(uintptr_t)buf;
143 	aiov.iov_len = count;
144 	auio.uio_iov = &aiov;
145 	auio.uio_iovcnt = 1;
146 	auio.uio_segflg = UIO_SYSSPACE;
147 	auio.uio_resid = count;
148 	auio.uio_rw = UIO_READ;
149 	auio.uio_td = td;
150 	auio.uio_offset = *offp;
151 
152 	if ((fp->f_flag & FREAD) == 0)
153 		return (SET_ERROR(EBADF));
154 
155 	rc = fo_read(fp, &auio, td->td_ucred, FOF_OFFSET, td);
156 	if (rc)
157 		return (SET_ERROR(rc));
158 	if (resid)
159 		*resid = auio.uio_resid;
160 	*offp += count - auio.uio_resid;
161 	return (SET_ERROR(0));
162 }
163 
164 int
165 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid)
166 {
167 	loff_t off = fp->f_offset;
168 	ssize_t rc;
169 
170 	rc = zfs_file_read_impl(fp, buf, count, &off, resid);
171 	if (rc == 0)
172 		fp->f_offset = off;
173 	return (rc);
174 }
175 
176 int
177 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off,
178     ssize_t *resid)
179 {
180 	return (zfs_file_read_impl(fp, buf, count, &off, resid));
181 }
182 
183 int
184 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence)
185 {
186 	int rc;
187 	struct thread *td;
188 
189 	td = curthread;
190 	if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
191 		return (SET_ERROR(ESPIPE));
192 	rc = fo_seek(fp, *offp, whence, td);
193 	if (rc == 0)
194 		*offp = td->td_uretoff.tdu_off;
195 	return (SET_ERROR(rc));
196 }
197 
198 int
199 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr)
200 {
201 	struct thread *td;
202 	struct stat sb;
203 	int rc;
204 
205 	td = curthread;
206 
207 #if __FreeBSD_version < 1400037
208 	rc = fo_stat(fp, &sb, td->td_ucred, td);
209 #else
210 	rc = fo_stat(fp, &sb, td->td_ucred);
211 #endif
212 	if (rc)
213 		return (SET_ERROR(rc));
214 	zfattr->zfa_size = sb.st_size;
215 	zfattr->zfa_mode = sb.st_mode;
216 
217 	return (0);
218 }
219 
220 static __inline int
221 zfs_vop_fsync(vnode_t *vp)
222 {
223 	struct mount *mp;
224 	int error;
225 
226 #if __FreeBSD_version < 1400068
227 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
228 #else
229 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
230 #endif
231 		goto drop;
232 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
233 	error = VOP_FSYNC(vp, MNT_WAIT, curthread);
234 	VOP_UNLOCK1(vp);
235 	vn_finished_write(mp);
236 drop:
237 	return (SET_ERROR(error));
238 }
239 
240 int
241 zfs_file_fsync(zfs_file_t *fp, int flags)
242 {
243 	if (fp->f_type != DTYPE_VNODE)
244 		return (EINVAL);
245 
246 	return (zfs_vop_fsync(fp->f_vnode));
247 }
248 
249 zfs_file_t *
250 zfs_file_get(int fd)
251 {
252 	struct file *fp;
253 
254 	if (fget(curthread, fd, &cap_no_rights, &fp))
255 		return (NULL);
256 
257 	return (fp);
258 }
259 
260 void
261 zfs_file_put(zfs_file_t *fp)
262 {
263 	fdrop(fp, curthread);
264 }
265 
266 loff_t
267 zfs_file_off(zfs_file_t *fp)
268 {
269 	return (fp->f_offset);
270 }
271 
272 void *
273 zfs_file_private(zfs_file_t *fp)
274 {
275 	file_t *tmpfp;
276 	void *data;
277 	int error;
278 
279 	tmpfp = curthread->td_fpop;
280 	curthread->td_fpop = fp;
281 	error = devfs_get_cdevpriv(&data);
282 	curthread->td_fpop = tmpfp;
283 	if (error != 0)
284 		return (NULL);
285 	return (data);
286 }
287 
288 int
289 zfs_file_unlink(const char *fnamep)
290 {
291 	zfs_uio_seg_t seg = UIO_SYSSPACE;
292 	int rc;
293 
294 #if __FreeBSD_version >= 1300018
295 	rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0);
296 #elif __FreeBSD_version >= 1202504 || defined(AT_BENEATH)
297 	rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
298 	    seg, 0, 0);
299 #else
300 	rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
301 	    seg, 0);
302 #endif
303 	return (SET_ERROR(rc));
304 }
305