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