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 struct vnode *vp; 54 struct file *fp; 55 struct nameidata nd; 56 int error; 57 58 td = curthread; 59 pwd_ensure_dirs(); 60 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); 66 67 error = falloc_noinstall(td, &fp); 68 if (error != 0) { 69 return (error); 70 } 71 fp->f_flag = flags & FMASK; 72 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)); 82 } 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); 88 } 89 VOP_UNLOCK(vp); 90 if (vp->v_type != VREG) { 91 zfs_file_close(fp); 92 return (SET_ERROR(EACCES)); 93 } 94 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)); 100 } 101 } 102 103 *fpp = fp; 104 105 return (0); 106 } 107 108 void 109 zfs_file_close(zfs_file_t *fp) 110 { 111 fdrop(fp, curthread); 112 } 113 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) 117 { 118 ssize_t rc; 119 struct uio auio; 120 struct thread *td; 121 struct iovec aiov; 122 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; 133 134 if ((fp->f_flag & FWRITE) == 0) 135 return (SET_ERROR(EBADF)); 136 137 if (fp->f_type == DTYPE_VNODE) 138 bwillwrite(); 139 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); 149 } 150 151 int 152 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid) 153 { 154 loff_t off = fp->f_offset; 155 ssize_t rc; 156 157 rc = zfs_file_write_impl(fp, buf, count, &off, resid); 158 if (rc == 0) 159 fp->f_offset = off; 160 161 return (SET_ERROR(rc)); 162 } 163 164 int 165 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off, 166 ssize_t *resid) 167 { 168 return (zfs_file_write_impl(fp, buf, count, &off, resid)); 169 } 170 171 static int 172 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp, 173 ssize_t *resid) 174 { 175 ssize_t rc; 176 struct uio auio; 177 struct thread *td; 178 struct iovec aiov; 179 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; 190 191 if ((fp->f_flag & FREAD) == 0) 192 return (SET_ERROR(EBADF)); 193 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)); 201 } 202 203 int 204 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid) 205 { 206 loff_t off = fp->f_offset; 207 ssize_t rc; 208 209 rc = zfs_file_read_impl(fp, buf, count, &off, resid); 210 if (rc == 0) 211 fp->f_offset = off; 212 return (rc); 213 } 214 215 int 216 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off, 217 ssize_t *resid) 218 { 219 return (zfs_file_read_impl(fp, buf, count, &off, resid)); 220 } 221 222 int 223 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence) 224 { 225 int rc; 226 struct thread *td; 227 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)); 235 } 236 237 int 238 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr) 239 { 240 struct thread *td; 241 struct stat sb; 242 int rc; 243 244 td = curthread; 245 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; 255 256 return (0); 257 } 258 259 static __inline int 260 zfs_vop_fsync(vnode_t *vp) 261 { 262 struct mount *mp; 263 int error; 264 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_UNLOCK1(vp); 274 vn_finished_write(mp); 275 drop: 276 return (SET_ERROR(error)); 277 } 278 279 int 280 zfs_file_fsync(zfs_file_t *fp, int flags) 281 { 282 if (fp->f_type != DTYPE_VNODE) 283 return (EINVAL); 284 285 return (zfs_vop_fsync(fp->f_vnode)); 286 } 287 288 zfs_file_t * 289 zfs_file_get(int fd) 290 { 291 struct file *fp; 292 293 if (fget(curthread, fd, &cap_no_rights, &fp)) 294 return (NULL); 295 296 return (fp); 297 } 298 299 void 300 zfs_file_put(zfs_file_t *fp) 301 { 302 zfs_file_close(fp); 303 } 304 305 loff_t 306 zfs_file_off(zfs_file_t *fp) 307 { 308 return (fp->f_offset); 309 } 310 311 void * 312 zfs_file_private(zfs_file_t *fp) 313 { 314 file_t *tmpfp; 315 void *data; 316 int error; 317 318 tmpfp = curthread->td_fpop; 319 curthread->td_fpop = fp; 320 error = devfs_get_cdevpriv(&data); 321 curthread->td_fpop = tmpfp; 322 if (error != 0) 323 return (NULL); 324 return (data); 325 } 326 327 int 328 zfs_file_unlink(const char *fnamep) 329 { 330 zfs_uio_seg_t seg = UIO_SYSSPACE; 331 int rc; 332 333 #if __FreeBSD_version >= 1300018 334 rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0); 335 #elif __FreeBSD_version >= 1202504 || defined(AT_BENEATH) 336 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep), 337 seg, 0, 0); 338 #else 339 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep), 340 seg, 0); 341 #endif 342 return (SET_ERROR(rc)); 343 } 344