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