2 * Copyright (c) 2020 iXsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/dmu_impl.h>
30 #include <sys/dmu_recv.h>
31 #include <sys/dmu_tx.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>
43 #include <sys/zio_checksum.h>
44 #include <sys/zfs_znode.h>
45 #include <sys/zfs_file.h>
50 zfs_file_open(const char *path
, int flags
, int mode
, zfs_file_t
**fpp
)
61 KASSERT((flags
& (O_EXEC
| O_PATH
)) == 0,
62 ("invalid flags: 0x%x", flags
));
63 KASSERT((flags
& O_ACCMODE
) != O_ACCMODE
,
64 ("invalid flags: 0x%x", flags
));
65 flags
= FFLAGS(flags
);
67 error
= falloc_noinstall(td
, &fp
);
71 fp
->f_flag
= flags
& FMASK
;
73 #if __FreeBSD_version >= 1400043
74 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, path
);
76 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, path
, td
);
78 error
= vn_open(&nd
, &flags
, mode
, fp
);
81 return (SET_ERROR(error
));
86 if (fp
->f_ops
== &badfileops
) {
87 finit_vnode(fp
, flags
, NULL
, &vnops
);
90 if (vp
->v_type
!= VREG
) {
92 return (SET_ERROR(EACCES
));
95 if (flags
& O_TRUNC
) {
96 error
= fo_truncate(fp
, 0, td
->td_ucred
, td
);
99 return (SET_ERROR(error
));
109 zfs_file_close(zfs_file_t
*fp
)
111 fdrop(fp
, curthread
);
115 zfs_file_write_impl(zfs_file_t
*fp
, const void *buf
, size_t count
, loff_t
*offp
,
124 aiov
.iov_base
= (void *)(uintptr_t)buf
;
125 aiov
.iov_len
= count
;
126 auio
.uio_iov
= &aiov
;
128 auio
.uio_segflg
= UIO_SYSSPACE
;
129 auio
.uio_resid
= count
;
130 auio
.uio_rw
= UIO_WRITE
;
132 auio
.uio_offset
= *offp
;
134 if ((fp
->f_flag
& FWRITE
) == 0)
135 return (SET_ERROR(EBADF
));
137 if (fp
->f_type
== DTYPE_VNODE
)
140 rc
= fo_write(fp
, &auio
, td
->td_ucred
, FOF_OFFSET
, td
);
142 return (SET_ERROR(rc
));
144 *resid
= auio
.uio_resid
;
145 else if (auio
.uio_resid
)
146 return (SET_ERROR(EIO
));
147 *offp
+= count
- auio
.uio_resid
;
152 zfs_file_write(zfs_file_t
*fp
, const void *buf
, size_t count
, ssize_t
*resid
)
154 loff_t off
= fp
->f_offset
;
157 rc
= zfs_file_write_impl(fp
, buf
, count
, &off
, resid
);
161 return (SET_ERROR(rc
));
165 zfs_file_pwrite(zfs_file_t
*fp
, const void *buf
, size_t count
, loff_t off
,
168 return (zfs_file_write_impl(fp
, buf
, count
, &off
, resid
));
172 zfs_file_read_impl(zfs_file_t
*fp
, void *buf
, size_t count
, loff_t
*offp
,
181 aiov
.iov_base
= (void *)(uintptr_t)buf
;
182 aiov
.iov_len
= count
;
183 auio
.uio_iov
= &aiov
;
185 auio
.uio_segflg
= UIO_SYSSPACE
;
186 auio
.uio_resid
= count
;
187 auio
.uio_rw
= UIO_READ
;
189 auio
.uio_offset
= *offp
;
191 if ((fp
->f_flag
& FREAD
) == 0)
192 return (SET_ERROR(EBADF
));
194 rc
= fo_read(fp
, &auio
, td
->td_ucred
, FOF_OFFSET
, td
);
196 return (SET_ERROR(rc
));
198 *resid
= auio
.uio_resid
;
199 *offp
+= count
- auio
.uio_resid
;
200 return (SET_ERROR(0));
204 zfs_file_read(zfs_file_t
*fp
, void *buf
, size_t count
, ssize_t
*resid
)
206 loff_t off
= fp
->f_offset
;
209 rc
= zfs_file_read_impl(fp
, buf
, count
, &off
, resid
);
216 zfs_file_pread(zfs_file_t
*fp
, void *buf
, size_t count
, loff_t off
,
219 return (zfs_file_read_impl(fp
, buf
, count
, &off
, resid
));
223 zfs_file_seek(zfs_file_t
*fp
, loff_t
*offp
, int whence
)
229 if ((fp
->f_ops
->fo_flags
& DFLAG_SEEKABLE
) == 0)
230 return (SET_ERROR(ESPIPE
));
231 rc
= fo_seek(fp
, *offp
, whence
, td
);
233 *offp
= td
->td_uretoff
.tdu_off
;
234 return (SET_ERROR(rc
));
238 zfs_file_getattr(zfs_file_t
*fp
, zfs_file_attr_t
*zfattr
)
246 #if __FreeBSD_version < 1400037
247 rc
= fo_stat(fp
, &sb
, td
->td_ucred
, td
);
249 rc
= fo_stat(fp
, &sb
, td
->td_ucred
);
252 return (SET_ERROR(rc
));
253 zfattr
->zfa_size
= sb
.st_size
;
254 zfattr
->zfa_mode
= sb
.st_mode
;
260 zfs_vop_fsync(vnode_t
*vp
)
265 #if __FreeBSD_version < 1400068
266 if ((error
= vn_start_write(vp
, &mp
, V_WAIT
| PCATCH
)) != 0)
268 if ((error
= vn_start_write(vp
, &mp
, V_WAIT
| V_PCATCH
)) != 0)
271 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
272 error
= VOP_FSYNC(vp
, MNT_WAIT
, curthread
);
274 vn_finished_write(mp
);
276 return (SET_ERROR(error
));
280 zfs_file_fsync(zfs_file_t
*fp
, int flags
)
282 if (fp
->f_type
!= DTYPE_VNODE
)
285 return (zfs_vop_fsync(fp
->f_vnode
));
289 * deallocate - zero and/or deallocate file storage
292 * offset - offset to start zeroing or deallocating
293 * len - length to zero or deallocate
296 zfs_file_deallocate(zfs_file_t
*fp
, loff_t offset
, loff_t len
)
299 #if __FreeBSD_version >= 1400029
303 rc
= fo_fspacectl(fp
, SPACECTL_DEALLOC
, &offset
, &len
, 0,
306 (void) fp
, (void) offset
, (void) len
;
310 return (SET_ERROR(rc
));
319 if (fget(curthread
, fd
, &cap_no_rights
, &fp
))
326 zfs_file_put(zfs_file_t
*fp
)
332 zfs_file_off(zfs_file_t
*fp
)
334 return (fp
->f_offset
);
338 zfs_file_private(zfs_file_t
*fp
)
344 tmpfp
= curthread
->td_fpop
;
345 curthread
->td_fpop
= fp
;
346 error
= devfs_get_cdevpriv(&data
);
347 curthread
->td_fpop
= tmpfp
;
354 zfs_file_unlink(const char *fnamep
)
356 zfs_uio_seg_t seg
= UIO_SYSSPACE
;
359 rc
= kern_funlinkat(curthread
, AT_FDCWD
, fnamep
, FD_NONE
, seg
, 0, 0);
360 return (SET_ERROR(rc
));