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