1 /* $NetBSD: ufs_vnops.c,v 1.231 2015/09/01 06:09:23 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1989, 1993, 1995 34 * The Regents of the University of California. All rights reserved. 35 * (c) UNIX System Laboratories, Inc. 36 * All or some portions of this file are derived from material licensed 37 * to the University of California by American Telephone and Telegraph 38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 39 * the permission of UNIX System Laboratories, Inc. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95 66 */ 67 68 #include <sys/cdefs.h> 69 __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.231 2015/09/01 06:09:23 dholland Exp $"); 70 71 #if defined(_KERNEL_OPT) 72 #include "opt_ffs.h" 73 #include "opt_quota.h" 74 #endif 75 76 #include <sys/param.h> 77 #include <sys/systm.h> 78 #include <sys/namei.h> 79 #include <sys/resourcevar.h> 80 #include <sys/kernel.h> 81 #include <sys/file.h> 82 #include <sys/stat.h> 83 #include <sys/buf.h> 84 #include <sys/proc.h> 85 #include <sys/mount.h> 86 #include <sys/vnode.h> 87 #include <sys/kmem.h> 88 #include <sys/malloc.h> 89 #include <sys/dirent.h> 90 #include <sys/lockf.h> 91 #include <sys/kauth.h> 92 #include <sys/wapbl.h> 93 #include <sys/fstrans.h> 94 95 #include <miscfs/specfs/specdev.h> 96 #include <miscfs/fifofs/fifo.h> 97 #include <miscfs/genfs/genfs.h> 98 99 #include <ufs/ufs/inode.h> 100 #include <ufs/ufs/dir.h> 101 #include <ufs/ufs/ufsmount.h> 102 #include <ufs/ufs/ufs_bswap.h> 103 #include <ufs/ufs/ufs_extern.h> 104 #include <ufs/ufs/ufs_wapbl.h> 105 #ifdef UFS_DIRHASH 106 #include <ufs/ufs/dirhash.h> 107 #endif 108 #include <ufs/ext2fs/ext2fs_extern.h> 109 #include <ufs/ext2fs/ext2fs_dir.h> 110 #include <ufs/ffs/ffs_extern.h> 111 #include <ufs/lfs/lfs_extern.h> 112 #include <ufs/lfs/lfs.h> 113 114 #include <uvm/uvm.h> 115 116 __CTASSERT(EXT2FS_MAXNAMLEN == FFS_MAXNAMLEN); 117 __CTASSERT(LFS_MAXNAMLEN == FFS_MAXNAMLEN); 118 119 static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *); 120 static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, 121 struct lwp *); 122 static int ufs_makeinode(struct vattr *, struct vnode *, 123 const struct ufs_lookup_results *, struct vnode **, struct componentname *); 124 125 /* 126 * A virgin directory (no blushing please). 127 */ 128 static const struct dirtemplate mastertemplate = { 129 0, 12, DT_DIR, 1, ".", 130 0, UFS_DIRBLKSIZ - 12, DT_DIR, 2, ".." 131 }; 132 133 /* 134 * Create a regular file 135 */ 136 int 137 ufs_create(void *v) 138 { 139 struct vop_create_v3_args /* { 140 struct vnode *a_dvp; 141 struct vnode **a_vpp; 142 struct componentname *a_cnp; 143 struct vattr *a_vap; 144 } */ *ap = v; 145 int error; 146 struct vnode *dvp = ap->a_dvp; 147 struct ufs_lookup_results *ulr; 148 149 /* XXX should handle this material another way */ 150 ulr = &VTOI(dvp)->i_crap; 151 UFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 152 153 /* 154 * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful 155 * ufs_makeinode 156 */ 157 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 158 error = ufs_makeinode(ap->a_vap, dvp, ulr, ap->a_vpp, ap->a_cnp); 159 if (error) { 160 fstrans_done(dvp->v_mount); 161 return (error); 162 } 163 UFS_WAPBL_END1(dvp->v_mount, dvp); 164 fstrans_done(dvp->v_mount); 165 VN_KNOTE(dvp, NOTE_WRITE); 166 VOP_UNLOCK(*ap->a_vpp); 167 return (0); 168 } 169 170 /* 171 * Mknod vnode call 172 */ 173 /* ARGSUSED */ 174 int 175 ufs_mknod(void *v) 176 { 177 struct vop_mknod_v3_args /* { 178 struct vnode *a_dvp; 179 struct vnode **a_vpp; 180 struct componentname *a_cnp; 181 struct vattr *a_vap; 182 } */ *ap = v; 183 struct vattr *vap; 184 struct vnode **vpp; 185 struct inode *ip; 186 int error; 187 struct ufs_lookup_results *ulr; 188 189 vap = ap->a_vap; 190 vpp = ap->a_vpp; 191 192 /* XXX should handle this material another way */ 193 ulr = &VTOI(ap->a_dvp)->i_crap; 194 UFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp)); 195 196 /* 197 * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful 198 * ufs_makeinode 199 */ 200 fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); 201 if ((error = ufs_makeinode(vap, ap->a_dvp, ulr, vpp, ap->a_cnp)) != 0) 202 goto out; 203 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 204 ip = VTOI(*vpp); 205 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 206 UFS_WAPBL_UPDATE(*vpp, NULL, NULL, 0); 207 UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp); 208 VOP_UNLOCK(*vpp); 209 out: 210 fstrans_done(ap->a_dvp->v_mount); 211 if (error != 0) { 212 *vpp = NULL; 213 return (error); 214 } 215 return (0); 216 } 217 218 /* 219 * Open called. 220 * 221 * Nothing to do. 222 */ 223 /* ARGSUSED */ 224 int 225 ufs_open(void *v) 226 { 227 struct vop_open_args /* { 228 struct vnode *a_vp; 229 int a_mode; 230 kauth_cred_t a_cred; 231 } */ *ap = v; 232 233 /* 234 * Files marked append-only must be opened for appending. 235 */ 236 if ((VTOI(ap->a_vp)->i_flags & APPEND) && 237 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 238 return (EPERM); 239 return (0); 240 } 241 242 /* 243 * Close called. 244 * 245 * Update the times on the inode. 246 */ 247 /* ARGSUSED */ 248 int 249 ufs_close(void *v) 250 { 251 struct vop_close_args /* { 252 struct vnode *a_vp; 253 int a_fflag; 254 kauth_cred_t a_cred; 255 } */ *ap = v; 256 struct vnode *vp; 257 258 vp = ap->a_vp; 259 fstrans_start(vp->v_mount, FSTRANS_SHARED); 260 if (vp->v_usecount > 1) 261 UFS_ITIMES(vp, NULL, NULL, NULL); 262 fstrans_done(vp->v_mount); 263 return (0); 264 } 265 266 static int 267 ufs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode, 268 kauth_cred_t cred) 269 { 270 #if defined(QUOTA) || defined(QUOTA2) 271 int error; 272 #endif 273 274 /* 275 * Disallow write attempts on read-only file systems; 276 * unless the file is a socket, fifo, or a block or 277 * character device resident on the file system. 278 */ 279 if (mode & VWRITE) { 280 switch (vp->v_type) { 281 case VDIR: 282 case VLNK: 283 case VREG: 284 if (vp->v_mount->mnt_flag & MNT_RDONLY) 285 return (EROFS); 286 #if defined(QUOTA) || defined(QUOTA2) 287 fstrans_start(vp->v_mount, FSTRANS_SHARED); 288 error = chkdq(ip, 0, cred, 0); 289 fstrans_done(vp->v_mount); 290 if (error != 0) 291 return error; 292 #endif 293 break; 294 case VBAD: 295 case VBLK: 296 case VCHR: 297 case VSOCK: 298 case VFIFO: 299 case VNON: 300 default: 301 break; 302 } 303 } 304 305 /* If it is a snapshot, nobody gets access to it. */ 306 if ((ip->i_flags & SF_SNAPSHOT)) 307 return (EPERM); 308 /* If immutable bit set, nobody gets to write it. */ 309 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE)) 310 return (EPERM); 311 312 return 0; 313 } 314 315 static int 316 ufs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode, 317 kauth_cred_t cred) 318 { 319 320 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type, 321 ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type, 322 ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred)); 323 } 324 325 int 326 ufs_access(void *v) 327 { 328 struct vop_access_args /* { 329 struct vnode *a_vp; 330 int a_mode; 331 kauth_cred_t a_cred; 332 } */ *ap = v; 333 struct vnode *vp; 334 struct inode *ip; 335 mode_t mode; 336 int error; 337 338 vp = ap->a_vp; 339 ip = VTOI(vp); 340 mode = ap->a_mode; 341 342 error = ufs_check_possible(vp, ip, mode, ap->a_cred); 343 if (error) 344 return error; 345 346 error = ufs_check_permitted(vp, ip, mode, ap->a_cred); 347 348 return error; 349 } 350 351 /* ARGSUSED */ 352 int 353 ufs_getattr(void *v) 354 { 355 struct vop_getattr_args /* { 356 struct vnode *a_vp; 357 struct vattr *a_vap; 358 kauth_cred_t a_cred; 359 } */ *ap = v; 360 struct vnode *vp; 361 struct inode *ip; 362 struct vattr *vap; 363 364 vp = ap->a_vp; 365 ip = VTOI(vp); 366 vap = ap->a_vap; 367 fstrans_start(vp->v_mount, FSTRANS_SHARED); 368 UFS_ITIMES(vp, NULL, NULL, NULL); 369 370 /* 371 * Copy from inode table 372 */ 373 vap->va_fsid = ip->i_dev; 374 vap->va_fileid = ip->i_number; 375 vap->va_mode = ip->i_mode & ALLPERMS; 376 vap->va_nlink = ip->i_nlink; 377 vap->va_uid = ip->i_uid; 378 vap->va_gid = ip->i_gid; 379 vap->va_size = vp->v_size; 380 if (ip->i_ump->um_fstype == UFS1) { 381 switch (vp->v_type) { 382 case VBLK: 383 case VCHR: 384 vap->va_rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev, 385 UFS_MPNEEDSWAP(ip->i_ump)); 386 break; 387 default: 388 vap->va_rdev = NODEV; 389 break; 390 } 391 vap->va_atime.tv_sec = ip->i_ffs1_atime; 392 vap->va_atime.tv_nsec = ip->i_ffs1_atimensec; 393 vap->va_mtime.tv_sec = ip->i_ffs1_mtime; 394 vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec; 395 vap->va_ctime.tv_sec = ip->i_ffs1_ctime; 396 vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec; 397 vap->va_birthtime.tv_sec = 0; 398 vap->va_birthtime.tv_nsec = 0; 399 vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks); 400 } else { 401 switch (vp->v_type) { 402 case VBLK: 403 case VCHR: 404 vap->va_rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev, 405 UFS_MPNEEDSWAP(ip->i_ump)); 406 break; 407 default: 408 vap->va_rdev = NODEV; 409 break; 410 } 411 vap->va_atime.tv_sec = ip->i_ffs2_atime; 412 vap->va_atime.tv_nsec = ip->i_ffs2_atimensec; 413 vap->va_mtime.tv_sec = ip->i_ffs2_mtime; 414 vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec; 415 vap->va_ctime.tv_sec = ip->i_ffs2_ctime; 416 vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec; 417 vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime; 418 vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec; 419 vap->va_bytes = dbtob(ip->i_ffs2_blocks); 420 } 421 vap->va_gen = ip->i_gen; 422 vap->va_flags = ip->i_flags; 423 424 /* this doesn't belong here */ 425 if (vp->v_type == VBLK) 426 vap->va_blocksize = BLKDEV_IOSIZE; 427 else if (vp->v_type == VCHR) 428 vap->va_blocksize = MAXBSIZE; 429 else 430 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 431 vap->va_type = vp->v_type; 432 vap->va_filerev = ip->i_modrev; 433 fstrans_done(vp->v_mount); 434 return (0); 435 } 436 437 /* 438 * Set attribute vnode op. called from several syscalls 439 */ 440 int 441 ufs_setattr(void *v) 442 { 443 struct vop_setattr_args /* { 444 struct vnode *a_vp; 445 struct vattr *a_vap; 446 kauth_cred_t a_cred; 447 } */ *ap = v; 448 struct vattr *vap; 449 struct vnode *vp; 450 struct inode *ip; 451 kauth_cred_t cred; 452 struct lwp *l; 453 int error; 454 kauth_action_t action; 455 bool changing_sysflags; 456 457 vap = ap->a_vap; 458 vp = ap->a_vp; 459 ip = VTOI(vp); 460 cred = ap->a_cred; 461 l = curlwp; 462 action = KAUTH_VNODE_WRITE_FLAGS; 463 changing_sysflags = false; 464 465 /* 466 * Check for unsettable attributes. 467 */ 468 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 469 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 470 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 471 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 472 return (EINVAL); 473 } 474 475 fstrans_start(vp->v_mount, FSTRANS_SHARED); 476 477 if (vap->va_flags != VNOVAL) { 478 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 479 error = EROFS; 480 goto out; 481 } 482 483 /* Snapshot flag cannot be set or cleared */ 484 if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) != 485 (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) { 486 error = EPERM; 487 goto out; 488 } 489 490 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) { 491 action |= KAUTH_VNODE_HAS_SYSFLAGS; 492 } 493 494 if ((vap->va_flags & SF_SETTABLE) != 495 (ip->i_flags & SF_SETTABLE)) { 496 action |= KAUTH_VNODE_WRITE_SYSFLAGS; 497 changing_sysflags = true; 498 } 499 500 error = kauth_authorize_vnode(cred, action, vp, NULL, 501 genfs_can_chflags(cred, vp->v_type, ip->i_uid, 502 changing_sysflags)); 503 if (error) 504 goto out; 505 506 if (changing_sysflags) { 507 error = UFS_WAPBL_BEGIN(vp->v_mount); 508 if (error) 509 goto out; 510 ip->i_flags = vap->va_flags; 511 DIP_ASSIGN(ip, flags, ip->i_flags); 512 } else { 513 error = UFS_WAPBL_BEGIN(vp->v_mount); 514 if (error) 515 goto out; 516 ip->i_flags &= SF_SETTABLE; 517 ip->i_flags |= (vap->va_flags & UF_SETTABLE); 518 DIP_ASSIGN(ip, flags, ip->i_flags); 519 } 520 ip->i_flag |= IN_CHANGE; 521 UFS_WAPBL_UPDATE(vp, NULL, NULL, 0); 522 UFS_WAPBL_END(vp->v_mount); 523 if (vap->va_flags & (IMMUTABLE | APPEND)) { 524 error = 0; 525 goto out; 526 } 527 } 528 if (ip->i_flags & (IMMUTABLE | APPEND)) { 529 error = EPERM; 530 goto out; 531 } 532 /* 533 * Go through the fields and update iff not VNOVAL. 534 */ 535 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 536 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 537 error = EROFS; 538 goto out; 539 } 540 error = UFS_WAPBL_BEGIN(vp->v_mount); 541 if (error) 542 goto out; 543 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l); 544 UFS_WAPBL_END(vp->v_mount); 545 if (error) 546 goto out; 547 } 548 if (vap->va_size != VNOVAL) { 549 /* 550 * Disallow write attempts on read-only file systems; 551 * unless the file is a socket, fifo, or a block or 552 * character device resident on the file system. 553 */ 554 switch (vp->v_type) { 555 case VDIR: 556 error = EISDIR; 557 goto out; 558 case VCHR: 559 case VBLK: 560 case VFIFO: 561 break; 562 case VREG: 563 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 564 error = EROFS; 565 goto out; 566 } 567 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 568 error = EPERM; 569 goto out; 570 } 571 error = ufs_truncate(vp, vap->va_size, cred); 572 if (error) 573 goto out; 574 break; 575 default: 576 error = EOPNOTSUPP; 577 goto out; 578 } 579 } 580 ip = VTOI(vp); 581 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 582 vap->va_birthtime.tv_sec != VNOVAL) { 583 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 584 error = EROFS; 585 goto out; 586 } 587 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 588 error = EPERM; 589 goto out; 590 } 591 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 592 NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred)); 593 if (error) 594 goto out; 595 error = UFS_WAPBL_BEGIN(vp->v_mount); 596 if (error) 597 goto out; 598 if (vap->va_atime.tv_sec != VNOVAL) 599 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 600 ip->i_flag |= IN_ACCESS; 601 if (vap->va_mtime.tv_sec != VNOVAL) { 602 ip->i_flag |= IN_CHANGE | IN_UPDATE; 603 if (vp->v_mount->mnt_flag & MNT_RELATIME) 604 ip->i_flag |= IN_ACCESS; 605 } 606 if (vap->va_birthtime.tv_sec != VNOVAL && 607 ip->i_ump->um_fstype == UFS2) { 608 ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec; 609 ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec; 610 } 611 error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0); 612 UFS_WAPBL_END(vp->v_mount); 613 if (error) 614 goto out; 615 } 616 error = 0; 617 if (vap->va_mode != (mode_t)VNOVAL) { 618 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 619 error = EROFS; 620 goto out; 621 } 622 if ((ip->i_flags & SF_SNAPSHOT) != 0 && 623 (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | 624 S_IXOTH | S_IWOTH))) { 625 error = EPERM; 626 goto out; 627 } 628 error = UFS_WAPBL_BEGIN(vp->v_mount); 629 if (error) 630 goto out; 631 error = ufs_chmod(vp, (int)vap->va_mode, cred, l); 632 UFS_WAPBL_END(vp->v_mount); 633 } 634 VN_KNOTE(vp, NOTE_ATTRIB); 635 out: 636 fstrans_done(vp->v_mount); 637 return (error); 638 } 639 640 /* 641 * Change the mode on a file. 642 * Inode must be locked before calling. 643 */ 644 static int 645 ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) 646 { 647 struct inode *ip; 648 int error; 649 650 UFS_WAPBL_JLOCK_ASSERT(vp->v_mount); 651 652 ip = VTOI(vp); 653 654 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 655 NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode)); 656 if (error) 657 return (error); 658 659 fstrans_start(vp->v_mount, FSTRANS_SHARED); 660 ip->i_mode &= ~ALLPERMS; 661 ip->i_mode |= (mode & ALLPERMS); 662 ip->i_flag |= IN_CHANGE; 663 DIP_ASSIGN(ip, mode, ip->i_mode); 664 UFS_WAPBL_UPDATE(vp, NULL, NULL, 0); 665 fstrans_done(vp->v_mount); 666 return (0); 667 } 668 669 /* 670 * Perform chown operation on inode ip; 671 * inode must be locked prior to call. 672 */ 673 static int 674 ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 675 struct lwp *l) 676 { 677 struct inode *ip; 678 int error = 0; 679 #if defined(QUOTA) || defined(QUOTA2) 680 uid_t ouid; 681 gid_t ogid; 682 int64_t change; 683 #endif 684 ip = VTOI(vp); 685 error = 0; 686 687 if (uid == (uid_t)VNOVAL) 688 uid = ip->i_uid; 689 if (gid == (gid_t)VNOVAL) 690 gid = ip->i_gid; 691 692 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, 693 NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid)); 694 if (error) 695 return (error); 696 697 fstrans_start(vp->v_mount, FSTRANS_SHARED); 698 #if defined(QUOTA) || defined(QUOTA2) 699 ogid = ip->i_gid; 700 ouid = ip->i_uid; 701 change = DIP(ip, blocks); 702 (void) chkdq(ip, -change, cred, 0); 703 (void) chkiq(ip, -1, cred, 0); 704 #endif 705 ip->i_gid = gid; 706 DIP_ASSIGN(ip, gid, gid); 707 ip->i_uid = uid; 708 DIP_ASSIGN(ip, uid, uid); 709 #if defined(QUOTA) || defined(QUOTA2) 710 if ((error = chkdq(ip, change, cred, 0)) == 0) { 711 if ((error = chkiq(ip, 1, cred, 0)) == 0) 712 goto good; 713 else 714 (void) chkdq(ip, -change, cred, FORCE); 715 } 716 ip->i_gid = ogid; 717 DIP_ASSIGN(ip, gid, ogid); 718 ip->i_uid = ouid; 719 DIP_ASSIGN(ip, uid, ouid); 720 (void) chkdq(ip, change, cred, FORCE); 721 (void) chkiq(ip, 1, cred, FORCE); 722 fstrans_done(vp->v_mount); 723 return (error); 724 good: 725 #endif /* QUOTA || QUOTA2 */ 726 ip->i_flag |= IN_CHANGE; 727 UFS_WAPBL_UPDATE(vp, NULL, NULL, 0); 728 fstrans_done(vp->v_mount); 729 return (0); 730 } 731 732 int 733 ufs_remove(void *v) 734 { 735 struct vop_remove_args /* { 736 struct vnode *a_dvp; 737 struct vnode *a_vp; 738 struct componentname *a_cnp; 739 } */ *ap = v; 740 struct vnode *vp, *dvp; 741 struct inode *ip; 742 struct mount *mp; 743 int error; 744 struct ufs_lookup_results *ulr; 745 746 vp = ap->a_vp; 747 dvp = ap->a_dvp; 748 ip = VTOI(vp); 749 mp = dvp->v_mount; 750 KASSERT(mp == vp->v_mount); /* XXX Not stable without lock. */ 751 752 /* XXX should handle this material another way */ 753 ulr = &VTOI(dvp)->i_crap; 754 UFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 755 756 fstrans_start(mp, FSTRANS_SHARED); 757 if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) || 758 (VTOI(dvp)->i_flags & APPEND)) 759 error = EPERM; 760 else { 761 error = UFS_WAPBL_BEGIN(mp); 762 if (error == 0) { 763 error = ufs_dirremove(dvp, ulr, 764 ip, ap->a_cnp->cn_flags, 0); 765 UFS_WAPBL_END(mp); 766 } 767 } 768 VN_KNOTE(vp, NOTE_DELETE); 769 VN_KNOTE(dvp, NOTE_WRITE); 770 if (dvp == vp) 771 vrele(vp); 772 else 773 vput(vp); 774 vput(dvp); 775 fstrans_done(mp); 776 return (error); 777 } 778 779 /* 780 * ufs_link: create hard link. 781 */ 782 int 783 ufs_link(void *v) 784 { 785 struct vop_link_v2_args /* { 786 struct vnode *a_dvp; 787 struct vnode *a_vp; 788 struct componentname *a_cnp; 789 } */ *ap = v; 790 struct vnode *dvp = ap->a_dvp; 791 struct vnode *vp = ap->a_vp; 792 struct componentname *cnp = ap->a_cnp; 793 struct mount *mp = dvp->v_mount; 794 struct inode *ip; 795 struct direct *newdir; 796 int error; 797 struct ufs_lookup_results *ulr; 798 799 KASSERT(dvp != vp); 800 KASSERT(vp->v_type != VDIR); 801 KASSERT(mp == vp->v_mount); /* XXX Not stable without lock. */ 802 803 /* XXX should handle this material another way */ 804 ulr = &VTOI(dvp)->i_crap; 805 UFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 806 807 fstrans_start(mp, FSTRANS_SHARED); 808 error = vn_lock(vp, LK_EXCLUSIVE); 809 if (error) { 810 VOP_ABORTOP(dvp, cnp); 811 goto out2; 812 } 813 ip = VTOI(vp); 814 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 815 VOP_ABORTOP(dvp, cnp); 816 error = EMLINK; 817 goto out1; 818 } 819 if (ip->i_flags & (IMMUTABLE | APPEND)) { 820 VOP_ABORTOP(dvp, cnp); 821 error = EPERM; 822 goto out1; 823 } 824 error = UFS_WAPBL_BEGIN(mp); 825 if (error) { 826 VOP_ABORTOP(dvp, cnp); 827 goto out1; 828 } 829 ip->i_nlink++; 830 DIP_ASSIGN(ip, nlink, ip->i_nlink); 831 ip->i_flag |= IN_CHANGE; 832 error = UFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP); 833 if (!error) { 834 newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); 835 ufs_makedirentry(ip, cnp, newdir); 836 error = ufs_direnter(dvp, ulr, vp, newdir, cnp, NULL); 837 pool_cache_put(ufs_direct_cache, newdir); 838 } 839 if (error) { 840 ip->i_nlink--; 841 DIP_ASSIGN(ip, nlink, ip->i_nlink); 842 ip->i_flag |= IN_CHANGE; 843 UFS_WAPBL_UPDATE(vp, NULL, NULL, UPDATE_DIROP); 844 } 845 UFS_WAPBL_END(mp); 846 out1: 847 VOP_UNLOCK(vp); 848 out2: 849 VN_KNOTE(vp, NOTE_LINK); 850 VN_KNOTE(dvp, NOTE_WRITE); 851 fstrans_done(mp); 852 return (error); 853 } 854 855 /* 856 * whiteout vnode call 857 */ 858 int 859 ufs_whiteout(void *v) 860 { 861 struct vop_whiteout_args /* { 862 struct vnode *a_dvp; 863 struct componentname *a_cnp; 864 int a_flags; 865 } */ *ap = v; 866 struct vnode *dvp = ap->a_dvp; 867 struct componentname *cnp = ap->a_cnp; 868 struct direct *newdir; 869 int error; 870 struct ufsmount *ump = VFSTOUFS(dvp->v_mount); 871 struct ufs_lookup_results *ulr; 872 873 /* XXX should handle this material another way */ 874 ulr = &VTOI(dvp)->i_crap; 875 UFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 876 877 error = 0; 878 switch (ap->a_flags) { 879 case LOOKUP: 880 /* 4.4 format directories support whiteout operations */ 881 if (ump->um_maxsymlinklen > 0) 882 return (0); 883 return (EOPNOTSUPP); 884 885 case CREATE: 886 /* create a new directory whiteout */ 887 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 888 error = UFS_WAPBL_BEGIN(dvp->v_mount); 889 if (error) 890 break; 891 #ifdef DIAGNOSTIC 892 if (ump->um_maxsymlinklen <= 0) 893 panic("ufs_whiteout: old format filesystem"); 894 #endif 895 896 newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); 897 newdir->d_ino = UFS_WINO; 898 newdir->d_namlen = cnp->cn_namelen; 899 memcpy(newdir->d_name, cnp->cn_nameptr, 900 (size_t)cnp->cn_namelen); 901 newdir->d_name[cnp->cn_namelen] = '\0'; 902 newdir->d_type = DT_WHT; 903 error = ufs_direnter(dvp, ulr, NULL, newdir, cnp, NULL); 904 pool_cache_put(ufs_direct_cache, newdir); 905 break; 906 907 case DELETE: 908 /* remove an existing directory whiteout */ 909 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 910 error = UFS_WAPBL_BEGIN(dvp->v_mount); 911 if (error) 912 break; 913 #ifdef DIAGNOSTIC 914 if (ump->um_maxsymlinklen <= 0) 915 panic("ufs_whiteout: old format filesystem"); 916 #endif 917 918 cnp->cn_flags &= ~DOWHITEOUT; 919 error = ufs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0); 920 break; 921 default: 922 panic("ufs_whiteout: unknown op"); 923 /* NOTREACHED */ 924 } 925 UFS_WAPBL_END(dvp->v_mount); 926 fstrans_done(dvp->v_mount); 927 return (error); 928 } 929 930 int 931 ufs_mkdir(void *v) 932 { 933 struct vop_mkdir_v3_args /* { 934 struct vnode *a_dvp; 935 struct vnode **a_vpp; 936 struct componentname *a_cnp; 937 struct vattr *a_vap; 938 } */ *ap = v; 939 struct vnode *dvp = ap->a_dvp, *tvp; 940 struct vattr *vap = ap->a_vap; 941 struct componentname *cnp = ap->a_cnp; 942 struct inode *ip, *dp = VTOI(dvp); 943 struct buf *bp; 944 struct dirtemplate dirtemplate; 945 struct direct *newdir; 946 int error; 947 struct ufsmount *ump = dp->i_ump; 948 int dirblksiz = ump->um_dirblksiz; 949 struct ufs_lookup_results *ulr; 950 951 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 952 953 /* XXX should handle this material another way */ 954 ulr = &dp->i_crap; 955 UFS_CHECK_CRAPCOUNTER(dp); 956 957 KASSERT(vap->va_type == VDIR); 958 959 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 960 error = EMLINK; 961 goto out; 962 } 963 /* 964 * Must simulate part of ufs_makeinode here to acquire the inode, 965 * but not have it entered in the parent directory. The entry is 966 * made later after writing "." and ".." entries. 967 */ 968 error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, ap->a_vpp); 969 if (error) 970 goto out; 971 error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); 972 if (error) { 973 vrele(*ap->a_vpp); 974 *ap->a_vpp = NULL; 975 goto out; 976 } 977 error = UFS_WAPBL_BEGIN(ap->a_dvp->v_mount); 978 if (error) { 979 vput(*ap->a_vpp); 980 goto out; 981 } 982 983 tvp = *ap->a_vpp; 984 ip = VTOI(tvp); 985 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 986 ip->i_nlink = 2; 987 DIP_ASSIGN(ip, nlink, 2); 988 if (cnp->cn_flags & ISWHITEOUT) { 989 ip->i_flags |= UF_OPAQUE; 990 DIP_ASSIGN(ip, flags, ip->i_flags); 991 } 992 993 /* 994 * Bump link count in parent directory to reflect work done below. 995 * Should be done before reference is created so cleanup is 996 * possible if we crash. 997 */ 998 dp->i_nlink++; 999 DIP_ASSIGN(dp, nlink, dp->i_nlink); 1000 dp->i_flag |= IN_CHANGE; 1001 if ((error = UFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0) 1002 goto bad; 1003 1004 /* 1005 * Initialize directory with "." and ".." from static template. 1006 */ 1007 dirtemplate = mastertemplate; 1008 dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen; 1009 dirtemplate.dot_ino = ufs_rw32(ip->i_number, UFS_MPNEEDSWAP(ump)); 1010 dirtemplate.dotdot_ino = ufs_rw32(dp->i_number, UFS_MPNEEDSWAP(ump)); 1011 dirtemplate.dot_reclen = ufs_rw16(dirtemplate.dot_reclen, 1012 UFS_MPNEEDSWAP(ump)); 1013 dirtemplate.dotdot_reclen = ufs_rw16(dirtemplate.dotdot_reclen, 1014 UFS_MPNEEDSWAP(ump)); 1015 if (ump->um_maxsymlinklen <= 0) { 1016 #if BYTE_ORDER == LITTLE_ENDIAN 1017 if (UFS_MPNEEDSWAP(ump) == 0) 1018 #else 1019 if (UFS_MPNEEDSWAP(ump) != 0) 1020 #endif 1021 { 1022 dirtemplate.dot_type = dirtemplate.dot_namlen; 1023 dirtemplate.dotdot_type = dirtemplate.dotdot_namlen; 1024 dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0; 1025 } else 1026 dirtemplate.dot_type = dirtemplate.dotdot_type = 0; 1027 } 1028 if ((error = UFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred, 1029 B_CLRBUF, &bp)) != 0) 1030 goto bad; 1031 ip->i_size = dirblksiz; 1032 DIP_ASSIGN(ip, size, dirblksiz); 1033 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1034 uvm_vnp_setsize(tvp, ip->i_size); 1035 memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate); 1036 1037 /* 1038 * Directory set up, now install its entry in the parent directory. 1039 * We must write out the buffer containing the new directory body 1040 * before entering the new name in the parent. 1041 */ 1042 if ((error = VOP_BWRITE(bp->b_vp, bp)) != 0) 1043 goto bad; 1044 if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) { 1045 goto bad; 1046 } 1047 newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); 1048 ufs_makedirentry(ip, cnp, newdir); 1049 error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, bp); 1050 pool_cache_put(ufs_direct_cache, newdir); 1051 bad: 1052 if (error == 0) { 1053 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 1054 VOP_UNLOCK(tvp); 1055 UFS_WAPBL_END(dvp->v_mount); 1056 } else { 1057 dp->i_nlink--; 1058 DIP_ASSIGN(dp, nlink, dp->i_nlink); 1059 dp->i_flag |= IN_CHANGE; 1060 UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP); 1061 /* 1062 * No need to do an explicit UFS_TRUNCATE here, vrele will 1063 * do this for us because we set the link count to 0. 1064 */ 1065 ip->i_nlink = 0; 1066 DIP_ASSIGN(ip, nlink, 0); 1067 ip->i_flag |= IN_CHANGE; 1068 UFS_WAPBL_UPDATE(tvp, NULL, NULL, UPDATE_DIROP); 1069 UFS_WAPBL_END(dvp->v_mount); 1070 vput(tvp); 1071 } 1072 out: 1073 fstrans_done(dvp->v_mount); 1074 return (error); 1075 } 1076 1077 int 1078 ufs_rmdir(void *v) 1079 { 1080 struct vop_rmdir_args /* { 1081 struct vnode *a_dvp; 1082 struct vnode *a_vp; 1083 struct componentname *a_cnp; 1084 } */ *ap = v; 1085 struct vnode *vp, *dvp; 1086 struct componentname *cnp; 1087 struct inode *ip, *dp; 1088 int error; 1089 struct ufs_lookup_results *ulr; 1090 1091 vp = ap->a_vp; 1092 dvp = ap->a_dvp; 1093 cnp = ap->a_cnp; 1094 ip = VTOI(vp); 1095 dp = VTOI(dvp); 1096 1097 /* XXX should handle this material another way */ 1098 ulr = &dp->i_crap; 1099 UFS_CHECK_CRAPCOUNTER(dp); 1100 1101 /* 1102 * No rmdir "." or of mounted directories please. 1103 */ 1104 if (dp == ip || vp->v_mountedhere != NULL) { 1105 if (dp == ip) 1106 vrele(dvp); 1107 else 1108 vput(dvp); 1109 vput(vp); 1110 return (EINVAL); 1111 } 1112 1113 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 1114 1115 /* 1116 * Do not remove a directory that is in the process of being renamed. 1117 * Verify that the directory is empty (and valid). (Rmdir ".." won't 1118 * be valid since ".." will contain a reference to the current 1119 * directory and thus be non-empty.) 1120 */ 1121 error = 0; 1122 if (ip->i_nlink != 2 || 1123 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 1124 error = ENOTEMPTY; 1125 goto out; 1126 } 1127 if ((dp->i_flags & APPEND) || 1128 (ip->i_flags & (IMMUTABLE | APPEND))) { 1129 error = EPERM; 1130 goto out; 1131 } 1132 error = UFS_WAPBL_BEGIN(dvp->v_mount); 1133 if (error) 1134 goto out; 1135 /* 1136 * Delete reference to directory before purging 1137 * inode. If we crash in between, the directory 1138 * will be reattached to lost+found, 1139 */ 1140 error = ufs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1); 1141 if (error) { 1142 UFS_WAPBL_END(dvp->v_mount); 1143 goto out; 1144 } 1145 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 1146 cache_purge(dvp); 1147 /* 1148 * Truncate inode. The only stuff left in the directory is "." and 1149 * "..". The "." reference is inconsequential since we're quashing 1150 * it. 1151 */ 1152 dp->i_nlink--; 1153 DIP_ASSIGN(dp, nlink, dp->i_nlink); 1154 dp->i_flag |= IN_CHANGE; 1155 UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP); 1156 ip->i_nlink--; 1157 DIP_ASSIGN(ip, nlink, ip->i_nlink); 1158 ip->i_flag |= IN_CHANGE; 1159 error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred); 1160 cache_purge(vp); 1161 /* 1162 * Unlock the log while we still have reference to unlinked 1163 * directory vp so that it will not get locked for recycling 1164 */ 1165 UFS_WAPBL_END(dvp->v_mount); 1166 #ifdef UFS_DIRHASH 1167 if (ip->i_dirhash != NULL) 1168 ufsdirhash_free(ip); 1169 #endif 1170 out: 1171 VN_KNOTE(vp, NOTE_DELETE); 1172 vput(vp); 1173 fstrans_done(dvp->v_mount); 1174 vput(dvp); 1175 return (error); 1176 } 1177 1178 /* 1179 * symlink -- make a symbolic link 1180 */ 1181 int 1182 ufs_symlink(void *v) 1183 { 1184 struct vop_symlink_v3_args /* { 1185 struct vnode *a_dvp; 1186 struct vnode **a_vpp; 1187 struct componentname *a_cnp; 1188 struct vattr *a_vap; 1189 char *a_target; 1190 } */ *ap = v; 1191 struct vnode *vp, **vpp; 1192 struct inode *ip; 1193 int len, error; 1194 struct ufs_lookup_results *ulr; 1195 1196 vpp = ap->a_vpp; 1197 1198 /* XXX should handle this material another way */ 1199 ulr = &VTOI(ap->a_dvp)->i_crap; 1200 UFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp)); 1201 1202 /* 1203 * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful 1204 * ufs_makeinode 1205 */ 1206 fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); 1207 KASSERT(ap->a_vap->va_type == VLNK); 1208 error = ufs_makeinode(ap->a_vap, ap->a_dvp, ulr, vpp, ap->a_cnp); 1209 if (error) 1210 goto out; 1211 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 1212 vp = *vpp; 1213 len = strlen(ap->a_target); 1214 ip = VTOI(vp); 1215 /* 1216 * This test is off by one. um_maxsymlinklen contains the 1217 * number of bytes available, and we aren't storing a \0, so 1218 * the test should properly be <=. However, it cannot be 1219 * changed as this would break compatibility with existing fs 1220 * images -- see the way ufs_readlink() works. 1221 */ 1222 if (len < ip->i_ump->um_maxsymlinklen) { 1223 memcpy((char *)SHORTLINK(ip), ap->a_target, len); 1224 ip->i_size = len; 1225 DIP_ASSIGN(ip, size, len); 1226 uvm_vnp_setsize(vp, ip->i_size); 1227 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1228 if (vp->v_mount->mnt_flag & MNT_RELATIME) 1229 ip->i_flag |= IN_ACCESS; 1230 UFS_WAPBL_UPDATE(vp, NULL, NULL, 0); 1231 } else 1232 error = ufs_bufio(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1233 IO_NODELOCKED | IO_JOURNALLOCKED, ap->a_cnp->cn_cred, NULL, 1234 NULL); 1235 UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp); 1236 VOP_UNLOCK(vp); 1237 if (error) 1238 vrele(vp); 1239 out: 1240 fstrans_done(ap->a_dvp->v_mount); 1241 return (error); 1242 } 1243 1244 /* 1245 * Vnode op for reading directories. 1246 * 1247 * This routine handles converting from the on-disk directory format 1248 * "struct direct" to the in-memory format "struct dirent" as well as 1249 * byte swapping the entries if necessary. 1250 */ 1251 int 1252 ufs_readdir(void *v) 1253 { 1254 struct vop_readdir_args /* { 1255 struct vnode *a_vp; 1256 struct uio *a_uio; 1257 kauth_cred_t a_cred; 1258 int *a_eofflag; 1259 off_t **a_cookies; 1260 int *ncookies; 1261 } */ *ap = v; 1262 struct vnode *vp = ap->a_vp; 1263 struct direct *cdp, *ecdp; 1264 struct dirent *ndp; 1265 char *cdbuf, *ndbuf, *endp; 1266 struct uio auio, *uio; 1267 struct iovec aiov; 1268 int error; 1269 size_t count, ccount, rcount, cdbufsz, ndbufsz; 1270 off_t off, *ccp; 1271 off_t startoff; 1272 size_t skipbytes; 1273 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 1274 int nswap = UFS_MPNEEDSWAP(ump); 1275 #if BYTE_ORDER == LITTLE_ENDIAN 1276 int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0; 1277 #else 1278 int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0; 1279 #endif 1280 uio = ap->a_uio; 1281 count = uio->uio_resid; 1282 rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1)); 1283 1284 if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp)) 1285 return EINVAL; 1286 1287 startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1); 1288 skipbytes = uio->uio_offset - startoff; 1289 rcount += skipbytes; 1290 1291 auio.uio_iov = &aiov; 1292 auio.uio_iovcnt = 1; 1293 auio.uio_offset = startoff; 1294 auio.uio_resid = rcount; 1295 UIO_SETUP_SYSSPACE(&auio); 1296 auio.uio_rw = UIO_READ; 1297 cdbufsz = rcount; 1298 cdbuf = kmem_alloc(cdbufsz, KM_SLEEP); 1299 aiov.iov_base = cdbuf; 1300 aiov.iov_len = rcount; 1301 error = UFS_BUFRD(vp, &auio, 0, ap->a_cred); 1302 if (error != 0) { 1303 kmem_free(cdbuf, cdbufsz); 1304 return error; 1305 } 1306 1307 rcount -= auio.uio_resid; 1308 1309 cdp = (struct direct *)(void *)cdbuf; 1310 ecdp = (struct direct *)(void *)&cdbuf[rcount]; 1311 1312 ndbufsz = count; 1313 ndbuf = kmem_alloc(ndbufsz, KM_SLEEP); 1314 ndp = (struct dirent *)(void *)ndbuf; 1315 endp = &ndbuf[count]; 1316 1317 off = uio->uio_offset; 1318 if (ap->a_cookies) { 1319 ccount = rcount / _DIRENT_RECLEN(cdp, 1); 1320 ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), 1321 M_TEMP, M_WAITOK); 1322 } else { 1323 /* XXX: GCC */ 1324 ccount = 0; 1325 ccp = NULL; 1326 } 1327 1328 while (cdp < ecdp) { 1329 cdp->d_reclen = ufs_rw16(cdp->d_reclen, nswap); 1330 if (skipbytes > 0) { 1331 if (cdp->d_reclen <= skipbytes) { 1332 skipbytes -= cdp->d_reclen; 1333 cdp = _DIRENT_NEXT(cdp); 1334 continue; 1335 } 1336 /* 1337 * invalid cookie. 1338 */ 1339 error = EINVAL; 1340 goto out; 1341 } 1342 if (cdp->d_reclen == 0) { 1343 struct dirent *ondp = ndp; 1344 ndp->d_reclen = _DIRENT_MINSIZE(ndp); 1345 ndp = _DIRENT_NEXT(ndp); 1346 ondp->d_reclen = 0; 1347 cdp = ecdp; 1348 break; 1349 } 1350 if (needswap) { 1351 ndp->d_type = cdp->d_namlen; 1352 ndp->d_namlen = cdp->d_type; 1353 } else { 1354 ndp->d_type = cdp->d_type; 1355 ndp->d_namlen = cdp->d_namlen; 1356 } 1357 ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); 1358 if ((char *)(void *)ndp + ndp->d_reclen + 1359 _DIRENT_MINSIZE(ndp) > endp) 1360 break; 1361 ndp->d_fileno = ufs_rw32(cdp->d_ino, nswap); 1362 (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen); 1363 memset(&ndp->d_name[ndp->d_namlen], 0, 1364 ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); 1365 off += cdp->d_reclen; 1366 if (ap->a_cookies) { 1367 KASSERT(ccp - *(ap->a_cookies) < ccount); 1368 *(ccp++) = off; 1369 } 1370 ndp = _DIRENT_NEXT(ndp); 1371 cdp = _DIRENT_NEXT(cdp); 1372 } 1373 1374 count = ((char *)(void *)ndp - ndbuf); 1375 error = uiomove(ndbuf, count, uio); 1376 out: 1377 if (ap->a_cookies) { 1378 if (error) { 1379 free(*(ap->a_cookies), M_TEMP); 1380 *(ap->a_cookies) = NULL; 1381 *(ap->a_ncookies) = 0; 1382 } else { 1383 *ap->a_ncookies = ccp - *(ap->a_cookies); 1384 } 1385 } 1386 uio->uio_offset = off; 1387 kmem_free(ndbuf, ndbufsz); 1388 kmem_free(cdbuf, cdbufsz); 1389 *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; 1390 return error; 1391 } 1392 1393 /* 1394 * Return target name of a symbolic link 1395 */ 1396 int 1397 ufs_readlink(void *v) 1398 { 1399 struct vop_readlink_args /* { 1400 struct vnode *a_vp; 1401 struct uio *a_uio; 1402 kauth_cred_t a_cred; 1403 } */ *ap = v; 1404 struct vnode *vp = ap->a_vp; 1405 struct inode *ip = VTOI(vp); 1406 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 1407 int isize; 1408 1409 /* 1410 * The test against um_maxsymlinklen is off by one; it should 1411 * theoretically be <=, not <. However, it cannot be changed 1412 * as that would break compatibility with existing fs images. 1413 */ 1414 1415 isize = ip->i_size; 1416 if (isize < ump->um_maxsymlinklen || 1417 (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) { 1418 uiomove((char *)SHORTLINK(ip), isize, ap->a_uio); 1419 return (0); 1420 } 1421 return (UFS_BUFRD(vp, ap->a_uio, 0, ap->a_cred)); 1422 } 1423 1424 /* 1425 * Calculate the logical to physical mapping if not done already, 1426 * then call the device strategy routine. 1427 */ 1428 int 1429 ufs_strategy(void *v) 1430 { 1431 struct vop_strategy_args /* { 1432 struct vnode *a_vp; 1433 struct buf *a_bp; 1434 } */ *ap = v; 1435 struct buf *bp; 1436 struct vnode *vp; 1437 struct inode *ip; 1438 struct mount *mp; 1439 int error; 1440 1441 bp = ap->a_bp; 1442 vp = ap->a_vp; 1443 ip = VTOI(vp); 1444 if (vp->v_type == VBLK || vp->v_type == VCHR) 1445 panic("ufs_strategy: spec"); 1446 KASSERT(bp->b_bcount != 0); 1447 if (bp->b_blkno == bp->b_lblkno) { 1448 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, 1449 NULL); 1450 if (error) { 1451 bp->b_error = error; 1452 biodone(bp); 1453 return (error); 1454 } 1455 if (bp->b_blkno == -1) /* no valid data */ 1456 clrbuf(bp); 1457 } 1458 if (bp->b_blkno < 0) { /* block is not on disk */ 1459 biodone(bp); 1460 return (0); 1461 } 1462 vp = ip->i_devvp; 1463 1464 error = VOP_STRATEGY(vp, bp); 1465 if (error) 1466 return error; 1467 1468 if (!BUF_ISREAD(bp)) 1469 return 0; 1470 1471 mp = wapbl_vptomp(vp); 1472 if (mp == NULL || mp->mnt_wapbl_replay == NULL || 1473 !WAPBL_REPLAY_ISOPEN(mp) || 1474 !WAPBL_REPLAY_CAN_READ(mp, bp->b_blkno, bp->b_bcount)) 1475 return 0; 1476 1477 error = biowait(bp); 1478 if (error) 1479 return error; 1480 1481 error = WAPBL_REPLAY_READ(mp, bp->b_data, bp->b_blkno, bp->b_bcount); 1482 if (error) { 1483 mutex_enter(&bufcache_lock); 1484 SET(bp->b_cflags, BC_INVAL); 1485 mutex_exit(&bufcache_lock); 1486 } 1487 return error; 1488 } 1489 1490 /* 1491 * Print out the contents of an inode. 1492 */ 1493 int 1494 ufs_print(void *v) 1495 { 1496 struct vop_print_args /* { 1497 struct vnode *a_vp; 1498 } */ *ap = v; 1499 struct vnode *vp; 1500 struct inode *ip; 1501 1502 vp = ap->a_vp; 1503 ip = VTOI(vp); 1504 printf("tag VT_UFS, ino %llu, on dev %llu, %llu", 1505 (unsigned long long)ip->i_number, 1506 (unsigned long long)major(ip->i_dev), 1507 (unsigned long long)minor(ip->i_dev)); 1508 printf(" flags 0x%x, nlink %d\n", 1509 ip->i_flag, ip->i_nlink); 1510 printf("\tmode 0%o, owner %d, group %d, size %qd", 1511 ip->i_mode, ip->i_uid, ip->i_gid, 1512 (long long)ip->i_size); 1513 if (vp->v_type == VFIFO) 1514 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 1515 printf("\n"); 1516 return (0); 1517 } 1518 1519 /* 1520 * Read wrapper for special devices. 1521 */ 1522 int 1523 ufsspec_read(void *v) 1524 { 1525 struct vop_read_args /* { 1526 struct vnode *a_vp; 1527 struct uio *a_uio; 1528 int a_ioflag; 1529 kauth_cred_t a_cred; 1530 } */ *ap = v; 1531 1532 /* 1533 * Set access flag. 1534 */ 1535 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1536 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 1537 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); 1538 } 1539 1540 /* 1541 * Write wrapper for special devices. 1542 */ 1543 int 1544 ufsspec_write(void *v) 1545 { 1546 struct vop_write_args /* { 1547 struct vnode *a_vp; 1548 struct uio *a_uio; 1549 int a_ioflag; 1550 kauth_cred_t a_cred; 1551 } */ *ap = v; 1552 1553 /* 1554 * Set update and change flags. 1555 */ 1556 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1557 VTOI(ap->a_vp)->i_flag |= IN_MODIFY; 1558 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); 1559 } 1560 1561 /* 1562 * Close wrapper for special devices. 1563 * 1564 * Update the times on the inode then do device close. 1565 */ 1566 int 1567 ufsspec_close(void *v) 1568 { 1569 struct vop_close_args /* { 1570 struct vnode *a_vp; 1571 int a_fflag; 1572 kauth_cred_t a_cred; 1573 } */ *ap = v; 1574 struct vnode *vp; 1575 1576 vp = ap->a_vp; 1577 if (vp->v_usecount > 1) 1578 UFS_ITIMES(vp, NULL, NULL, NULL); 1579 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); 1580 } 1581 1582 /* 1583 * Read wrapper for fifo's 1584 */ 1585 int 1586 ufsfifo_read(void *v) 1587 { 1588 struct vop_read_args /* { 1589 struct vnode *a_vp; 1590 struct uio *a_uio; 1591 int a_ioflag; 1592 kauth_cred_t a_cred; 1593 } */ *ap = v; 1594 1595 /* 1596 * Set access flag. 1597 */ 1598 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 1599 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); 1600 } 1601 1602 /* 1603 * Write wrapper for fifo's. 1604 */ 1605 int 1606 ufsfifo_write(void *v) 1607 { 1608 struct vop_write_args /* { 1609 struct vnode *a_vp; 1610 struct uio *a_uio; 1611 int a_ioflag; 1612 kauth_cred_t a_cred; 1613 } */ *ap = v; 1614 1615 /* 1616 * Set update and change flags. 1617 */ 1618 VTOI(ap->a_vp)->i_flag |= IN_MODIFY; 1619 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); 1620 } 1621 1622 /* 1623 * Close wrapper for fifo's. 1624 * 1625 * Update the times on the inode then do device close. 1626 */ 1627 int 1628 ufsfifo_close(void *v) 1629 { 1630 struct vop_close_args /* { 1631 struct vnode *a_vp; 1632 int a_fflag; 1633 kauth_cred_t a_cred; 1634 } */ *ap = v; 1635 struct vnode *vp; 1636 1637 vp = ap->a_vp; 1638 if (ap->a_vp->v_usecount > 1) 1639 UFS_ITIMES(vp, NULL, NULL, NULL); 1640 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); 1641 } 1642 1643 /* 1644 * Return POSIX pathconf information applicable to ufs filesystems. 1645 */ 1646 int 1647 ufs_pathconf(void *v) 1648 { 1649 struct vop_pathconf_args /* { 1650 struct vnode *a_vp; 1651 int a_name; 1652 register_t *a_retval; 1653 } */ *ap = v; 1654 1655 switch (ap->a_name) { 1656 case _PC_LINK_MAX: 1657 *ap->a_retval = LINK_MAX; 1658 return (0); 1659 case _PC_NAME_MAX: 1660 *ap->a_retval = FFS_MAXNAMLEN; 1661 return (0); 1662 case _PC_PATH_MAX: 1663 *ap->a_retval = PATH_MAX; 1664 return (0); 1665 case _PC_PIPE_BUF: 1666 *ap->a_retval = PIPE_BUF; 1667 return (0); 1668 case _PC_CHOWN_RESTRICTED: 1669 *ap->a_retval = 1; 1670 return (0); 1671 case _PC_NO_TRUNC: 1672 *ap->a_retval = 1; 1673 return (0); 1674 case _PC_SYNC_IO: 1675 *ap->a_retval = 1; 1676 return (0); 1677 case _PC_FILESIZEBITS: 1678 *ap->a_retval = 42; 1679 return (0); 1680 case _PC_SYMLINK_MAX: 1681 *ap->a_retval = MAXPATHLEN; 1682 return (0); 1683 case _PC_2_SYMLINKS: 1684 *ap->a_retval = 1; 1685 return (0); 1686 default: 1687 return (EINVAL); 1688 } 1689 /* NOTREACHED */ 1690 } 1691 1692 /* 1693 * Advisory record locking support 1694 */ 1695 int 1696 ufs_advlock(void *v) 1697 { 1698 struct vop_advlock_args /* { 1699 struct vnode *a_vp; 1700 void * a_id; 1701 int a_op; 1702 struct flock *a_fl; 1703 int a_flags; 1704 } */ *ap = v; 1705 struct inode *ip; 1706 1707 ip = VTOI(ap->a_vp); 1708 return lf_advlock(ap, &ip->i_lockf, ip->i_size); 1709 } 1710 1711 /* 1712 * Initialize the vnode associated with a new inode, handle aliased 1713 * vnodes. 1714 */ 1715 void 1716 ufs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *), 1717 struct vnode **vpp) 1718 { 1719 struct timeval tv; 1720 struct inode *ip; 1721 struct vnode *vp; 1722 dev_t rdev; 1723 struct ufsmount *ump; 1724 1725 vp = *vpp; 1726 ip = VTOI(vp); 1727 switch(vp->v_type = IFTOVT(ip->i_mode)) { 1728 case VCHR: 1729 case VBLK: 1730 vp->v_op = specops; 1731 ump = ip->i_ump; 1732 if (ump->um_fstype == UFS1) 1733 rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev, 1734 UFS_MPNEEDSWAP(ump)); 1735 else 1736 rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev, 1737 UFS_MPNEEDSWAP(ump)); 1738 spec_node_init(vp, rdev); 1739 break; 1740 case VFIFO: 1741 vp->v_op = fifoops; 1742 break; 1743 case VNON: 1744 case VBAD: 1745 case VSOCK: 1746 case VLNK: 1747 case VDIR: 1748 case VREG: 1749 break; 1750 } 1751 if (ip->i_number == UFS_ROOTINO) 1752 vp->v_vflag |= VV_ROOT; 1753 /* 1754 * Initialize modrev times 1755 */ 1756 getmicrouptime(&tv); 1757 ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32 1758 | tv.tv_usec * 4294u; 1759 *vpp = vp; 1760 } 1761 1762 /* 1763 * Allocate a new inode. 1764 */ 1765 int 1766 ufs_makeinode(struct vattr *vap, struct vnode *dvp, 1767 const struct ufs_lookup_results *ulr, 1768 struct vnode **vpp, struct componentname *cnp) 1769 { 1770 struct inode *ip; 1771 struct direct *newdir; 1772 struct vnode *tvp; 1773 int error; 1774 1775 UFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount); 1776 1777 error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, &tvp); 1778 if (error) 1779 return error; 1780 error = vn_lock(tvp, LK_EXCLUSIVE); 1781 if (error) { 1782 vrele(tvp); 1783 return error; 1784 } 1785 *vpp = tvp; 1786 ip = VTOI(tvp); 1787 error = UFS_WAPBL_BEGIN1(dvp->v_mount, dvp); 1788 if (error) { 1789 vput(tvp); 1790 return (error); 1791 } 1792 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1793 ip->i_nlink = 1; 1794 DIP_ASSIGN(ip, nlink, 1); 1795 1796 /* Authorize setting SGID if needed. */ 1797 if (ip->i_mode & ISGID) { 1798 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, 1799 tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid, 1800 ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode))); 1801 if (error) { 1802 ip->i_mode &= ~ISGID; 1803 DIP_ASSIGN(ip, mode, ip->i_mode); 1804 } 1805 } 1806 1807 if (cnp->cn_flags & ISWHITEOUT) { 1808 ip->i_flags |= UF_OPAQUE; 1809 DIP_ASSIGN(ip, flags, ip->i_flags); 1810 } 1811 1812 /* 1813 * Make sure inode goes to disk before directory entry. 1814 */ 1815 if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) 1816 goto bad; 1817 newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); 1818 ufs_makedirentry(ip, cnp, newdir); 1819 error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, NULL); 1820 pool_cache_put(ufs_direct_cache, newdir); 1821 if (error) 1822 goto bad; 1823 *vpp = tvp; 1824 return (0); 1825 1826 bad: 1827 /* 1828 * Write error occurred trying to update the inode 1829 * or the directory so must deallocate the inode. 1830 */ 1831 ip->i_nlink = 0; 1832 DIP_ASSIGN(ip, nlink, 0); 1833 ip->i_flag |= IN_CHANGE; 1834 UFS_WAPBL_UPDATE(tvp, NULL, NULL, 0); 1835 UFS_WAPBL_END1(dvp->v_mount, dvp); 1836 vput(tvp); 1837 return (error); 1838 } 1839 1840 /* 1841 * Allocate len bytes at offset off. 1842 */ 1843 int 1844 ufs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 1845 kauth_cred_t cred) 1846 { 1847 struct inode *ip = VTOI(vp); 1848 int error, delta, bshift, bsize; 1849 UVMHIST_FUNC("ufs_gop_alloc"); UVMHIST_CALLED(ubchist); 1850 1851 error = 0; 1852 bshift = vp->v_mount->mnt_fs_bshift; 1853 bsize = 1 << bshift; 1854 1855 delta = off & (bsize - 1); 1856 off -= delta; 1857 len += delta; 1858 1859 while (len > 0) { 1860 bsize = MIN(bsize, len); 1861 1862 error = UFS_BALLOC(vp, off, bsize, cred, flags, NULL); 1863 if (error) { 1864 goto out; 1865 } 1866 1867 /* 1868 * increase file size now, UFS_BALLOC() requires that 1869 * EOF be up-to-date before each call. 1870 */ 1871 1872 if (ip->i_size < off + bsize) { 1873 UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x", 1874 vp, ip->i_size, off + bsize, 0); 1875 ip->i_size = off + bsize; 1876 DIP_ASSIGN(ip, size, ip->i_size); 1877 } 1878 1879 off += bsize; 1880 len -= bsize; 1881 } 1882 1883 out: 1884 UFS_WAPBL_UPDATE(vp, NULL, NULL, 0); 1885 return error; 1886 } 1887 1888 void 1889 ufs_gop_markupdate(struct vnode *vp, int flags) 1890 { 1891 u_int32_t mask = 0; 1892 1893 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 1894 mask = IN_ACCESS; 1895 } 1896 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 1897 if (vp->v_type == VREG) { 1898 mask |= IN_CHANGE | IN_UPDATE; 1899 } else { 1900 mask |= IN_MODIFY; 1901 } 1902 } 1903 if (mask) { 1904 struct inode *ip = VTOI(vp); 1905 1906 ip->i_flag |= mask; 1907 } 1908 } 1909 1910 int 1911 ufs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off, 1912 int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l) 1913 { 1914 struct iovec iov; 1915 struct uio uio; 1916 int error; 1917 1918 KASSERT(ISSET(ioflg, IO_NODELOCKED)); 1919 KASSERT(VOP_ISLOCKED(vp)); 1920 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1921 KASSERT(rw != UIO_WRITE || vp->v_mount->mnt_wapbl == NULL || 1922 ISSET(ioflg, IO_JOURNALLOCKED)); 1923 1924 iov.iov_base = buf; 1925 iov.iov_len = len; 1926 uio.uio_iov = &iov; 1927 uio.uio_iovcnt = 1; 1928 uio.uio_resid = len; 1929 uio.uio_offset = off; 1930 uio.uio_rw = rw; 1931 UIO_SETUP_SYSSPACE(&uio); 1932 1933 switch (rw) { 1934 case UIO_READ: 1935 error = UFS_BUFRD(vp, &uio, ioflg, cred); 1936 break; 1937 case UIO_WRITE: 1938 error = UFS_BUFWR(vp, &uio, ioflg, cred); 1939 break; 1940 default: 1941 panic("invalid uio rw: %d", (int)rw); 1942 } 1943 1944 if (aresid) 1945 *aresid = uio.uio_resid; 1946 else if (uio.uio_resid && error == 0) 1947 error = EIO; 1948 1949 KASSERT(VOP_ISLOCKED(vp)); 1950 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1951 return error; 1952 } 1953