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