1 /* 2 * Copyright (c) 2020 iXsystems, Inc. 3 * All rights reserved. 4 * 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. 13 * 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. 25 * 26 */ 27 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> 48 49 int 50 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp) 51 { 52 struct thread *td; 53 int rc, fd; 54 55 td = curthread; 56 pwd_ensure_dirs(); 57 /* 12.x doesn't take a const char * */ 58 rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path), 59 UIO_SYSSPACE, flags, mode); 60 if (rc) 61 return (SET_ERROR(rc)); 62 fd = td->td_retval[0]; 63 td->td_retval[0] = 0; 64 if (fget(curthread, fd, &cap_no_rights, fpp)) 65 kern_close(td, fd); 66 return (0); 67 } 68 69 void 70 zfs_file_close(zfs_file_t *fp) 71 { 72 fo_close(fp, curthread); 73 } 74 75 static int 76 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp, 77 ssize_t *resid) 78 { 79 ssize_t rc; 80 struct uio auio; 81 struct thread *td; 82 struct iovec aiov; 83 84 td = curthread; 85 aiov.iov_base = (void *)(uintptr_t)buf; 86 aiov.iov_len = count; 87 auio.uio_iov = &aiov; 88 auio.uio_iovcnt = 1; 89 auio.uio_segflg = UIO_SYSSPACE; 90 auio.uio_resid = count; 91 auio.uio_rw = UIO_WRITE; 92 auio.uio_td = td; 93 auio.uio_offset = *offp; 94 95 if ((fp->f_flag & FWRITE) == 0) 96 return (SET_ERROR(EBADF)); 97 98 if (fp->f_type == DTYPE_VNODE) 99 bwillwrite(); 100 101 rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td); 102 if (rc) 103 return (SET_ERROR(rc)); 104 if (resid) 105 *resid = auio.uio_resid; 106 else if (auio.uio_resid) 107 return (SET_ERROR(EIO)); 108 *offp += count - auio.uio_resid; 109 return (rc); 110 } 111 112 int 113 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid) 114 { 115 loff_t off = fp->f_offset; 116 ssize_t rc; 117 118 rc = zfs_file_write_impl(fp, buf, count, &off, resid); 119 if (rc == 0) 120 fp->f_offset = off; 121 122 return (SET_ERROR(rc)); 123 } 124 125 int 126 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off, 127 ssize_t *resid) 128 { 129 return (zfs_file_write_impl(fp, buf, count, &off, resid)); 130 } 131 132 static int 133 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp, 134 ssize_t *resid) 135 { 136 ssize_t rc; 137 struct uio auio; 138 struct thread *td; 139 struct iovec aiov; 140 141 td = curthread; 142 aiov.iov_base = (void *)(uintptr_t)buf; 143 aiov.iov_len = count; 144 auio.uio_iov = &aiov; 145 auio.uio_iovcnt = 1; 146 auio.uio_segflg = UIO_SYSSPACE; 147 auio.uio_resid = count; 148 auio.uio_rw = UIO_READ; 149 auio.uio_td = td; 150 auio.uio_offset = *offp; 151 152 if ((fp->f_flag & FREAD) == 0) 153 return (SET_ERROR(EBADF)); 154 155 rc = fo_read(fp, &auio, td->td_ucred, FOF_OFFSET, td); 156 if (rc) 157 return (SET_ERROR(rc)); 158 if (resid) 159 *resid = auio.uio_resid; 160 *offp += count - auio.uio_resid; 161 return (SET_ERROR(0)); 162 } 163 164 int 165 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid) 166 { 167 loff_t off = fp->f_offset; 168 ssize_t rc; 169 170 rc = zfs_file_read_impl(fp, buf, count, &off, resid); 171 if (rc == 0) 172 fp->f_offset = off; 173 return (rc); 174 } 175 176 int 177 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off, 178 ssize_t *resid) 179 { 180 return (zfs_file_read_impl(fp, buf, count, &off, resid)); 181 } 182 183 int 184 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence) 185 { 186 int rc; 187 struct thread *td; 188 189 td = curthread; 190 if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) 191 return (SET_ERROR(ESPIPE)); 192 rc = fo_seek(fp, *offp, whence, td); 193 if (rc == 0) 194 *offp = td->td_uretoff.tdu_off; 195 return (SET_ERROR(rc)); 196 } 197 198 int 199 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr) 200 { 201 struct thread *td; 202 struct stat sb; 203 int rc; 204 205 td = curthread; 206 207 #if __FreeBSD_version < 1400037 208 rc = fo_stat(fp, &sb, td->td_ucred, td); 209 #else 210 rc = fo_stat(fp, &sb, td->td_ucred); 211 #endif 212 if (rc) 213 return (SET_ERROR(rc)); 214 zfattr->zfa_size = sb.st_size; 215 zfattr->zfa_mode = sb.st_mode; 216 217 return (0); 218 } 219 220 static __inline int 221 zfs_vop_fsync(vnode_t *vp) 222 { 223 struct mount *mp; 224 int error; 225 226 #if __FreeBSD_version < 1400068 227 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 228 #else 229 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) 230 #endif 231 goto drop; 232 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 233 error = VOP_FSYNC(vp, MNT_WAIT, curthread); 234 VOP_UNLOCK1(vp); 235 vn_finished_write(mp); 236 drop: 237 return (SET_ERROR(error)); 238 } 239 240 int 241 zfs_file_fsync(zfs_file_t *fp, int flags) 242 { 243 if (fp->f_type != DTYPE_VNODE) 244 return (EINVAL); 245 246 return (zfs_vop_fsync(fp->f_vnode)); 247 } 248 249 zfs_file_t * 250 zfs_file_get(int fd) 251 { 252 struct file *fp; 253 254 if (fget(curthread, fd, &cap_no_rights, &fp)) 255 return (NULL); 256 257 return (fp); 258 } 259 260 void 261 zfs_file_put(zfs_file_t *fp) 262 { 263 fdrop(fp, curthread); 264 } 265 266 loff_t 267 zfs_file_off(zfs_file_t *fp) 268 { 269 return (fp->f_offset); 270 } 271 272 void * 273 zfs_file_private(zfs_file_t *fp) 274 { 275 file_t *tmpfp; 276 void *data; 277 int error; 278 279 tmpfp = curthread->td_fpop; 280 curthread->td_fpop = fp; 281 error = devfs_get_cdevpriv(&data); 282 curthread->td_fpop = tmpfp; 283 if (error != 0) 284 return (NULL); 285 return (data); 286 } 287 288 int 289 zfs_file_unlink(const char *fnamep) 290 { 291 zfs_uio_seg_t seg = UIO_SYSSPACE; 292 int rc; 293 294 #if __FreeBSD_version >= 1300018 295 rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0); 296 #elif __FreeBSD_version >= 1202504 || defined(AT_BENEATH) 297 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep), 298 seg, 0, 0); 299 #else 300 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep), 301 seg, 0); 302 #endif 303 return (SET_ERROR(rc)); 304 } 305