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