flush: only detect lack of flush support in one place
[zfs.git] / module / os / freebsd / zfs / zfs_file_os.c
blobf6ee391dedddd6083affd02c0de610f0d30bcbcb
1 /*
2 * Copyright (c) 2020 iXsystems, Inc.
3 * All rights reserved.
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.
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.
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>
49 int
50 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
52 struct thread *td;
53 struct vnode *vp;
54 struct file *fp;
55 struct nameidata nd;
56 int error;
58 td = curthread;
59 pwd_ensure_dirs();
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);
68 if (error != 0) {
69 return (error);
71 fp->f_flag = flags & FMASK;
73 #if __FreeBSD_version >= 1400043
74 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path);
75 #else
76 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
77 #endif
78 error = vn_open(&nd, &flags, mode, fp);
79 if (error != 0) {
80 falloc_abort(td, fp);
81 return (SET_ERROR(error));
83 NDFREE_PNBUF(&nd);
84 vp = nd.ni_vp;
85 fp->f_vnode = vp;
86 if (fp->f_ops == &badfileops) {
87 finit_vnode(fp, flags, NULL, &vnops);
89 VOP_UNLOCK(vp);
90 if (vp->v_type != VREG) {
91 zfs_file_close(fp);
92 return (SET_ERROR(EACCES));
95 if (flags & O_TRUNC) {
96 error = fo_truncate(fp, 0, td->td_ucred, td);
97 if (error != 0) {
98 zfs_file_close(fp);
99 return (SET_ERROR(error));
103 *fpp = fp;
105 return (0);
108 void
109 zfs_file_close(zfs_file_t *fp)
111 fdrop(fp, curthread);
114 static int
115 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp,
116 ssize_t *resid)
118 ssize_t rc;
119 struct uio auio;
120 struct thread *td;
121 struct iovec aiov;
123 td = curthread;
124 aiov.iov_base = (void *)(uintptr_t)buf;
125 aiov.iov_len = count;
126 auio.uio_iov = &aiov;
127 auio.uio_iovcnt = 1;
128 auio.uio_segflg = UIO_SYSSPACE;
129 auio.uio_resid = count;
130 auio.uio_rw = UIO_WRITE;
131 auio.uio_td = td;
132 auio.uio_offset = *offp;
134 if ((fp->f_flag & FWRITE) == 0)
135 return (SET_ERROR(EBADF));
137 if (fp->f_type == DTYPE_VNODE)
138 bwillwrite();
140 rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td);
141 if (rc)
142 return (SET_ERROR(rc));
143 if (resid)
144 *resid = auio.uio_resid;
145 else if (auio.uio_resid)
146 return (SET_ERROR(EIO));
147 *offp += count - auio.uio_resid;
148 return (rc);
152 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
154 loff_t off = fp->f_offset;
155 ssize_t rc;
157 rc = zfs_file_write_impl(fp, buf, count, &off, resid);
158 if (rc == 0)
159 fp->f_offset = off;
161 return (SET_ERROR(rc));
165 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
166 ssize_t *resid)
168 return (zfs_file_write_impl(fp, buf, count, &off, resid));
171 static int
172 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp,
173 ssize_t *resid)
175 ssize_t rc;
176 struct uio auio;
177 struct thread *td;
178 struct iovec aiov;
180 td = curthread;
181 aiov.iov_base = (void *)(uintptr_t)buf;
182 aiov.iov_len = count;
183 auio.uio_iov = &aiov;
184 auio.uio_iovcnt = 1;
185 auio.uio_segflg = UIO_SYSSPACE;
186 auio.uio_resid = count;
187 auio.uio_rw = UIO_READ;
188 auio.uio_td = td;
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);
195 if (rc)
196 return (SET_ERROR(rc));
197 if (resid)
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;
207 ssize_t rc;
209 rc = zfs_file_read_impl(fp, buf, count, &off, resid);
210 if (rc == 0)
211 fp->f_offset = off;
212 return (rc);
216 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off,
217 ssize_t *resid)
219 return (zfs_file_read_impl(fp, buf, count, &off, resid));
223 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence)
225 int rc;
226 struct thread *td;
228 td = curthread;
229 if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
230 return (SET_ERROR(ESPIPE));
231 rc = fo_seek(fp, *offp, whence, td);
232 if (rc == 0)
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)
240 struct thread *td;
241 struct stat sb;
242 int rc;
244 td = curthread;
246 #if __FreeBSD_version < 1400037
247 rc = fo_stat(fp, &sb, td->td_ucred, td);
248 #else
249 rc = fo_stat(fp, &sb, td->td_ucred);
250 #endif
251 if (rc)
252 return (SET_ERROR(rc));
253 zfattr->zfa_size = sb.st_size;
254 zfattr->zfa_mode = sb.st_mode;
256 return (0);
259 static __inline int
260 zfs_vop_fsync(vnode_t *vp)
262 struct mount *mp;
263 int error;
265 #if __FreeBSD_version < 1400068
266 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
267 #else
268 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
269 #endif
270 goto drop;
271 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
272 error = VOP_FSYNC(vp, MNT_WAIT, curthread);
273 VOP_UNLOCK(vp);
274 vn_finished_write(mp);
275 drop:
276 return (SET_ERROR(error));
280 zfs_file_fsync(zfs_file_t *fp, int flags)
282 if (fp->f_type != DTYPE_VNODE)
283 return (EINVAL);
285 return (zfs_vop_fsync(fp->f_vnode));
289 * deallocate - zero and/or deallocate file storage
291 * fp - file pointer
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)
298 int rc;
299 #if __FreeBSD_version >= 1400029
300 struct thread *td;
302 td = curthread;
303 rc = fo_fspacectl(fp, SPACECTL_DEALLOC, &offset, &len, 0,
304 td->td_ucred, td);
305 #else
306 (void) fp, (void) offset, (void) len;
307 rc = EOPNOTSUPP;
308 #endif
309 if (rc)
310 return (SET_ERROR(rc));
311 return (0);
314 zfs_file_t *
315 zfs_file_get(int fd)
317 struct file *fp;
319 if (fget(curthread, fd, &cap_no_rights, &fp))
320 return (NULL);
322 return (fp);
325 void
326 zfs_file_put(zfs_file_t *fp)
328 zfs_file_close(fp);
331 loff_t
332 zfs_file_off(zfs_file_t *fp)
334 return (fp->f_offset);
337 void *
338 zfs_file_private(zfs_file_t *fp)
340 file_t *tmpfp;
341 void *data;
342 int error;
344 tmpfp = curthread->td_fpop;
345 curthread->td_fpop = fp;
346 error = devfs_get_cdevpriv(&data);
347 curthread->td_fpop = tmpfp;
348 if (error != 0)
349 return (NULL);
350 return (data);
354 zfs_file_unlink(const char *fnamep)
356 zfs_uio_seg_t seg = UIO_SYSSPACE;
357 int rc;
359 rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0);
360 return (SET_ERROR(rc));