1 /* $NetBSD: ulfs_vnops.c,v 1.56 2022/03/27 16:24:59 christos Exp $ */ 2 /* from NetBSD: ufs_vnops.c,v 1.232 2016/05/19 18:32:03 riastradh Exp */ 3 4 /*- 5 * Copyright (c) 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Wasabi Systems, Inc. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1989, 1993, 1995 35 * The Regents of the University of California. All rights reserved. 36 * (c) UNIX System Laboratories, Inc. 37 * All or some portions of this file are derived from material licensed 38 * to the University of California by American Telephone and Telegraph 39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 40 * the permission of UNIX System Laboratories, Inc. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.56 2022/03/27 16:24:59 christos Exp $"); 71 72 #if defined(_KERNEL_OPT) 73 #include "opt_lfs.h" 74 #include "opt_quota.h" 75 #include "opt_uvmhist.h" 76 #endif 77 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/namei.h> 81 #include <sys/resourcevar.h> 82 #include <sys/kernel.h> 83 #include <sys/file.h> 84 #include <sys/stat.h> 85 #include <sys/buf.h> 86 #include <sys/proc.h> 87 #include <sys/mount.h> 88 #include <sys/vnode.h> 89 #include <sys/kmem.h> 90 #include <sys/malloc.h> 91 #include <sys/dirent.h> 92 #include <sys/lockf.h> 93 #include <sys/kauth.h> 94 95 #include <miscfs/specfs/specdev.h> 96 #include <miscfs/fifofs/fifo.h> 97 #include <miscfs/genfs/genfs.h> 98 99 #include <ufs/lfs/lfs_extern.h> 100 #include <ufs/lfs/lfs.h> 101 #include <ufs/lfs/lfs_accessors.h> 102 103 #include <ufs/lfs/ulfs_inode.h> 104 #include <ufs/lfs/ulfsmount.h> 105 #include <ufs/lfs/ulfs_bswap.h> 106 #include <ufs/lfs/ulfs_extern.h> 107 #ifdef LFS_DIRHASH 108 #include <ufs/lfs/ulfs_dirhash.h> 109 #endif 110 111 #ifdef UVMHIST 112 #include <uvm/uvm.h> 113 #endif 114 #include <uvm/uvm_stat.h> 115 116 static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *); 117 static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, 118 struct lwp *); 119 120 /* 121 * Open called. 122 * 123 * Nothing to do. 124 */ 125 /* ARGSUSED */ 126 int 127 ulfs_open(void *v) 128 { 129 struct vop_open_args /* { 130 struct vnode *a_vp; 131 int a_mode; 132 kauth_cred_t a_cred; 133 } */ *ap = v; 134 135 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 136 137 /* 138 * Files marked append-only must be opened for appending. 139 */ 140 if ((VTOI(ap->a_vp)->i_flags & APPEND) && 141 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 142 return (EPERM); 143 return (0); 144 } 145 146 static int 147 ulfs_check_possible(struct vnode *vp, struct inode *ip, accmode_t accmode, 148 kauth_cred_t cred) 149 { 150 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 151 int error; 152 #endif 153 154 /* 155 * Disallow write attempts on read-only file systems; 156 * unless the file is a socket, fifo, or a block or 157 * character device resident on the file system. 158 */ 159 if (accmode & VWRITE) { 160 switch (vp->v_type) { 161 case VDIR: 162 case VLNK: 163 case VREG: 164 if (vp->v_mount->mnt_flag & MNT_RDONLY) 165 return (EROFS); 166 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 167 error = lfs_chkdq(ip, 0, cred, 0); 168 if (error != 0) 169 return error; 170 #endif 171 break; 172 case VBAD: 173 case VBLK: 174 case VCHR: 175 case VSOCK: 176 case VFIFO: 177 case VNON: 178 default: 179 break; 180 } 181 } 182 183 /* If it is a snapshot, nobody gets access to it. */ 184 if ((ip->i_flags & SF_SNAPSHOT)) 185 return (EPERM); 186 /* If immutable bit set, nobody gets to write it. */ 187 if ((accmode & VWRITE) && (ip->i_flags & IMMUTABLE)) 188 return (EPERM); 189 190 return 0; 191 } 192 193 static int 194 ulfs_check_permitted(struct vnode *vp, struct inode *ip, accmode_t accmode, 195 kauth_cred_t cred) 196 { 197 198 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode, 199 vp->v_type, ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access( 200 vp, cred, ip->i_uid, ip->i_gid, ip->i_mode & ALLPERMS, 201 NULL, accmode)); 202 } 203 204 int 205 ulfs_access(void *v) 206 { 207 struct vop_access_args /* { 208 struct vnode *a_vp; 209 accmode_t a_accmode; 210 kauth_cred_t a_cred; 211 } */ *ap = v; 212 struct vnode *vp; 213 struct inode *ip; 214 accmode_t accmode; 215 int error; 216 217 vp = ap->a_vp; 218 accmode = ap->a_accmode; 219 220 KASSERT(VOP_ISLOCKED(vp)); 221 222 ip = VTOI(vp); 223 224 error = ulfs_check_possible(vp, ip, accmode, ap->a_cred); 225 if (error) 226 return error; 227 228 error = ulfs_check_permitted(vp, ip, accmode, ap->a_cred); 229 230 return error; 231 } 232 233 /* 234 * Set attribute vnode op. called from several syscalls 235 */ 236 int 237 ulfs_setattr(void *v) 238 { 239 struct vop_setattr_args /* { 240 struct vnode *a_vp; 241 struct vattr *a_vap; 242 kauth_cred_t a_cred; 243 } */ *ap = v; 244 struct vattr *vap; 245 struct vnode *vp; 246 struct inode *ip; 247 struct lfs *fs; 248 kauth_cred_t cred; 249 struct lwp *l; 250 int error; 251 kauth_action_t action; 252 bool changing_sysflags; 253 254 vap = ap->a_vap; 255 vp = ap->a_vp; 256 cred = ap->a_cred; 257 l = curlwp; 258 action = KAUTH_VNODE_WRITE_FLAGS; 259 changing_sysflags = false; 260 261 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 262 263 ip = VTOI(vp); 264 fs = ip->i_lfs; 265 266 /* 267 * Check for unsettable attributes. 268 */ 269 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 270 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 271 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 272 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 273 return (EINVAL); 274 } 275 276 if (vap->va_flags != VNOVAL) { 277 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 278 error = EROFS; 279 goto out; 280 } 281 282 /* Snapshot flag cannot be set or cleared */ 283 if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) != 284 (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) { 285 error = EPERM; 286 goto out; 287 } 288 289 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) { 290 action |= KAUTH_VNODE_HAS_SYSFLAGS; 291 } 292 293 if ((vap->va_flags & SF_SETTABLE) != 294 (ip->i_flags & SF_SETTABLE)) { 295 action |= KAUTH_VNODE_WRITE_SYSFLAGS; 296 changing_sysflags = true; 297 } 298 299 error = kauth_authorize_vnode(cred, action, vp, NULL, 300 genfs_can_chflags(vp, cred, ip->i_uid, 301 changing_sysflags)); 302 if (error) 303 goto out; 304 305 if (changing_sysflags) { 306 ip->i_flags = vap->va_flags; 307 DIP_ASSIGN(ip, flags, ip->i_flags); 308 } else { 309 ip->i_flags &= SF_SETTABLE; 310 ip->i_flags |= (vap->va_flags & UF_SETTABLE); 311 DIP_ASSIGN(ip, flags, ip->i_flags); 312 } 313 ip->i_state |= IN_CHANGE; 314 if (vap->va_flags & (IMMUTABLE | APPEND)) { 315 error = 0; 316 goto out; 317 } 318 } 319 if (ip->i_flags & (IMMUTABLE | APPEND)) { 320 error = EPERM; 321 goto out; 322 } 323 /* 324 * Go through the fields and update iff not VNOVAL. 325 */ 326 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 327 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 328 error = EROFS; 329 goto out; 330 } 331 error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); 332 if (error) 333 goto out; 334 } 335 if (vap->va_size != VNOVAL) { 336 /* 337 * Disallow write attempts on read-only file systems; 338 * unless the file is a socket, fifo, or a block or 339 * character device resident on the file system. 340 */ 341 switch (vp->v_type) { 342 case VDIR: 343 error = EISDIR; 344 goto out; 345 case VCHR: 346 case VBLK: 347 case VFIFO: 348 break; 349 case VREG: 350 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 351 error = EROFS; 352 goto out; 353 } 354 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 355 error = EPERM; 356 goto out; 357 } 358 error = lfs_truncate(vp, vap->va_size, 0, cred); 359 if (error) 360 goto out; 361 break; 362 default: 363 error = EOPNOTSUPP; 364 goto out; 365 } 366 } 367 ip = VTOI(vp); 368 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 369 vap->va_birthtime.tv_sec != VNOVAL) { 370 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 371 error = EROFS; 372 goto out; 373 } 374 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 375 error = EPERM; 376 goto out; 377 } 378 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 379 NULL, genfs_can_chtimes(vp, cred, ip->i_uid, 380 vap->va_vaflags)); 381 if (error) 382 goto out; 383 if (vap->va_atime.tv_sec != VNOVAL) 384 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 385 ip->i_state |= IN_ACCESS; 386 if (vap->va_mtime.tv_sec != VNOVAL) { 387 ip->i_state |= IN_CHANGE | IN_UPDATE; 388 if (vp->v_mount->mnt_flag & MNT_RELATIME) 389 ip->i_state |= IN_ACCESS; 390 } 391 if (vap->va_birthtime.tv_sec != VNOVAL) { 392 lfs_dino_setbirthtime(fs, ip->i_din, 393 &vap->va_birthtime); 394 } 395 error = lfs_update(vp, &vap->va_atime, &vap->va_mtime, 0); 396 if (error) 397 goto out; 398 } 399 error = 0; 400 if (vap->va_mode != (mode_t)VNOVAL) { 401 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 402 error = EROFS; 403 goto out; 404 } 405 if ((ip->i_flags & SF_SNAPSHOT) != 0 && 406 (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | 407 S_IXOTH | S_IWOTH))) { 408 error = EPERM; 409 goto out; 410 } 411 error = ulfs_chmod(vp, (int)vap->va_mode, cred, l); 412 } 413 out: 414 return (error); 415 } 416 417 /* 418 * Change the mode on a file. 419 * Inode must be locked before calling. 420 */ 421 static int 422 ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) 423 { 424 struct inode *ip; 425 int error; 426 427 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 428 429 ip = VTOI(vp); 430 431 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 432 NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode)); 433 if (error) 434 return (error); 435 436 ip->i_mode &= ~ALLPERMS; 437 ip->i_mode |= (mode & ALLPERMS); 438 ip->i_state |= IN_CHANGE; 439 DIP_ASSIGN(ip, mode, ip->i_mode); 440 return (0); 441 } 442 443 /* 444 * Perform chown operation on inode ip; 445 * inode must be locked prior to call. 446 */ 447 static int 448 ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 449 struct lwp *l) 450 { 451 struct inode *ip; 452 int error = 0; 453 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 454 uid_t ouid; 455 gid_t ogid; 456 int64_t change; 457 #endif 458 459 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 460 461 ip = VTOI(vp); 462 error = 0; 463 464 if (uid == (uid_t)VNOVAL) 465 uid = ip->i_uid; 466 if (gid == (gid_t)VNOVAL) 467 gid = ip->i_gid; 468 469 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, 470 NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid)); 471 if (error) 472 return (error); 473 474 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 475 ogid = ip->i_gid; 476 ouid = ip->i_uid; 477 change = DIP(ip, blocks); 478 (void) lfs_chkdq(ip, -change, cred, 0); 479 (void) lfs_chkiq(ip, -1, cred, 0); 480 #endif 481 ip->i_gid = gid; 482 DIP_ASSIGN(ip, gid, gid); 483 ip->i_uid = uid; 484 DIP_ASSIGN(ip, uid, uid); 485 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 486 if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) { 487 if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0) 488 goto good; 489 else 490 (void) lfs_chkdq(ip, -change, cred, FORCE); 491 } 492 ip->i_gid = ogid; 493 DIP_ASSIGN(ip, gid, ogid); 494 ip->i_uid = ouid; 495 DIP_ASSIGN(ip, uid, ouid); 496 (void) lfs_chkdq(ip, change, cred, FORCE); 497 (void) lfs_chkiq(ip, 1, cred, FORCE); 498 return (error); 499 good: 500 #endif /* LFS_QUOTA || LFS_QUOTA2 */ 501 ip->i_state |= IN_CHANGE; 502 return (0); 503 } 504 505 int 506 ulfs_remove(void *v) 507 { 508 struct vop_remove_v3_args /* { 509 struct vnode *a_dvp; 510 struct vnode *a_vp; 511 struct componentname *a_cnp; 512 nlink_t ctx_vp_new_nlink; 513 } */ *ap = v; 514 struct vnode *vp, *dvp; 515 struct inode *ip; 516 int error; 517 struct ulfs_lookup_results *ulr; 518 519 dvp = ap->a_dvp; 520 vp = ap->a_vp; 521 522 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 523 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 524 KASSERT(dvp->v_mount == vp->v_mount); 525 526 ip = VTOI(vp); 527 528 /* XXX should handle this material another way */ 529 ulr = &VTOI(dvp)->i_crap; 530 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 531 532 if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) || 533 (VTOI(dvp)->i_flags & APPEND)) 534 error = EPERM; 535 else { 536 error = ulfs_dirremove(dvp, ulr, 537 ip, ap->a_cnp->cn_flags, 0); 538 if (error == 0) { 539 ap->ctx_vp_new_nlink = ip->i_nlink; 540 } 541 } 542 if (dvp == vp) 543 vrele(vp); 544 else 545 vput(vp); 546 return (error); 547 } 548 549 /* 550 * ulfs_link: create hard link. 551 */ 552 int 553 ulfs_link(void *v) 554 { 555 struct vop_link_v2_args /* { 556 struct vnode *a_dvp; 557 struct vnode *a_vp; 558 struct componentname *a_cnp; 559 } */ *ap = v; 560 struct vnode *dvp = ap->a_dvp; 561 struct vnode *vp = ap->a_vp; 562 struct componentname *cnp = ap->a_cnp; 563 struct inode *ip; 564 int error, abrt = 1; 565 struct ulfs_lookup_results *ulr; 566 567 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 568 KASSERT(dvp != vp); 569 KASSERT(vp->v_type != VDIR); 570 571 /* XXX should handle this material another way */ 572 ulr = &VTOI(dvp)->i_crap; 573 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 574 575 error = vn_lock(vp, LK_EXCLUSIVE); 576 if (error) 577 goto out2; 578 if (vp->v_mount != dvp->v_mount) { 579 error = ENOENT; 580 goto out2; 581 } 582 ip = VTOI(vp); 583 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 584 error = EMLINK; 585 goto out1; 586 } 587 if (ip->i_flags & (IMMUTABLE | APPEND)) { 588 error = EPERM; 589 goto out1; 590 } 591 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_ADD_LINK, vp, 592 dvp, 0); 593 if (error) 594 goto out1; 595 abrt = 0; 596 ip->i_nlink++; 597 DIP_ASSIGN(ip, nlink, ip->i_nlink); 598 ip->i_state |= IN_CHANGE; 599 error = lfs_update(vp, NULL, NULL, UPDATE_DIROP); 600 if (!error) { 601 error = ulfs_direnter(dvp, ulr, vp, 602 cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL); 603 } 604 if (error) { 605 ip->i_nlink--; 606 DIP_ASSIGN(ip, nlink, ip->i_nlink); 607 ip->i_state |= IN_CHANGE; 608 } 609 out1: 610 VOP_UNLOCK(vp); 611 if (abrt) 612 VOP_ABORTOP(dvp, cnp); 613 out2: 614 return (error); 615 } 616 617 /* 618 * whiteout vnode call 619 */ 620 int 621 ulfs_whiteout(void *v) 622 { 623 struct vop_whiteout_args /* { 624 struct vnode *a_dvp; 625 struct componentname *a_cnp; 626 int a_flags; 627 } */ *ap = v; 628 struct vnode *dvp = ap->a_dvp; 629 struct componentname *cnp = ap->a_cnp; 630 int error; 631 struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); 632 struct lfs *fs = ump->um_lfs; 633 struct ulfs_lookup_results *ulr; 634 635 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 636 637 /* XXX should handle this material another way */ 638 ulr = &VTOI(dvp)->i_crap; 639 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 640 641 error = 0; 642 switch (ap->a_flags) { 643 case LOOKUP: 644 /* 4.4 format directories support whiteout operations */ 645 if (fs->um_maxsymlinklen > 0) 646 return (0); 647 return (EOPNOTSUPP); 648 649 case CREATE: 650 /* create a new directory whiteout */ 651 KASSERTMSG((fs->um_maxsymlinklen > 0), 652 "ulfs_whiteout: old format filesystem"); 653 654 error = ulfs_direnter(dvp, ulr, NULL, 655 cnp, ULFS_WINO, LFS_DT_WHT, NULL); 656 break; 657 658 case DELETE: 659 /* remove an existing directory whiteout */ 660 KASSERTMSG((fs->um_maxsymlinklen > 0), 661 "ulfs_whiteout: old format filesystem"); 662 663 cnp->cn_flags &= ~DOWHITEOUT; 664 error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0); 665 break; 666 default: 667 panic("ulfs_whiteout: unknown op"); 668 /* NOTREACHED */ 669 } 670 return (error); 671 } 672 673 int 674 ulfs_rmdir(void *v) 675 { 676 struct vop_rmdir_v2_args /* { 677 struct vnode *a_dvp; 678 struct vnode *a_vp; 679 struct componentname *a_cnp; 680 } */ *ap = v; 681 struct vnode *vp, *dvp; 682 struct componentname *cnp; 683 struct inode *ip, *dp; 684 int error; 685 struct ulfs_lookup_results *ulr; 686 687 dvp = ap->a_dvp; 688 vp = ap->a_vp; 689 cnp = ap->a_cnp; 690 691 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 692 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 693 694 dp = VTOI(dvp); 695 ip = VTOI(vp); 696 697 /* XXX should handle this material another way */ 698 ulr = &dp->i_crap; 699 ULFS_CHECK_CRAPCOUNTER(dp); 700 701 /* 702 * No rmdir "." or of mounted directories please. 703 */ 704 if (dp == ip || vp->v_mountedhere != NULL) { 705 if (dp == ip) 706 vrele(vp); 707 else 708 vput(vp); 709 return (EINVAL); 710 } 711 712 /* 713 * Do not remove a directory that is in the process of being renamed. 714 * Verify that the directory is empty (and valid). (Rmdir ".." won't 715 * be valid since ".." will contain a reference to the current 716 * directory and thus be non-empty.) 717 */ 718 error = 0; 719 if (ip->i_nlink != 2 || 720 !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 721 error = ENOTEMPTY; 722 goto out; 723 } 724 if ((dp->i_flags & APPEND) || 725 (ip->i_flags & (IMMUTABLE | APPEND))) { 726 error = EPERM; 727 goto out; 728 } 729 /* 730 * Delete reference to directory before purging 731 * inode. If we crash in between, the directory 732 * will be reattached to lost+found, 733 */ 734 error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1); 735 if (error) { 736 goto out; 737 } 738 cache_purge(dvp); 739 /* 740 * Truncate inode. The only stuff left in the directory is "." and 741 * "..". The "." reference is inconsequential since we're quashing 742 * it. 743 */ 744 dp->i_nlink--; 745 DIP_ASSIGN(dp, nlink, dp->i_nlink); 746 dp->i_state |= IN_CHANGE; 747 ip->i_nlink--; 748 DIP_ASSIGN(ip, nlink, ip->i_nlink); 749 ip->i_state |= IN_CHANGE; 750 error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred); 751 cache_purge(vp); 752 #ifdef LFS_DIRHASH 753 if (ip->i_dirhash != NULL) 754 ulfsdirhash_free(ip); 755 #endif 756 out: 757 vput(vp); 758 return (error); 759 } 760 761 /* 762 * Vnode op for reading directories. 763 * 764 * This routine handles converting from the on-disk directory format 765 * "struct lfs_direct" to the in-memory format "struct dirent" as well as 766 * byte swapping the entries if necessary. 767 */ 768 int 769 ulfs_readdir(void *v) 770 { 771 struct vop_readdir_args /* { 772 struct vnode *a_vp; 773 struct uio *a_uio; 774 kauth_cred_t a_cred; 775 int *a_eofflag; 776 off_t **a_cookies; 777 int *a_ncookies; 778 } */ *ap = v; 779 780 /* vnode and fs */ 781 struct vnode *vp = ap->a_vp; 782 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 783 struct lfs *fs = ump->um_lfs; 784 /* caller's buffer */ 785 struct uio *calleruio = ap->a_uio; 786 off_t startoffset, endoffset; 787 size_t callerbytes; 788 off_t curoffset; 789 /* dirent production buffer */ 790 char *direntbuf; 791 size_t direntbufmax; 792 struct dirent *dirent, *stopdirent; 793 /* output cookies array */ 794 off_t *cookies; 795 size_t numcookies, maxcookies; 796 /* disk buffer */ 797 off_t physstart, physend; 798 size_t skipstart, dropend; 799 char *rawbuf; 800 size_t rawbufmax, rawbytes; 801 struct uio rawuio; 802 struct iovec rawiov; 803 LFS_DIRHEADER *rawdp, *stoprawdp; 804 /* general */ 805 int error; 806 807 KASSERT(VOP_ISLOCKED(vp)); 808 809 /* figure out where we want to read */ 810 callerbytes = calleruio->uio_resid; 811 startoffset = calleruio->uio_offset; 812 endoffset = startoffset + callerbytes; 813 814 if (callerbytes < _DIRENT_MINSIZE(dirent)) { 815 /* no room for even one struct dirent */ 816 return EINVAL; 817 } 818 819 /* round start and end down to block boundaries */ 820 physstart = startoffset & ~(off_t)(fs->um_dirblksiz - 1); 821 physend = endoffset & ~(off_t)(fs->um_dirblksiz - 1); 822 skipstart = startoffset - physstart; 823 dropend = endoffset - physend; 824 825 if (callerbytes - dropend < LFS_DIRECTSIZ(fs, 0)) { 826 /* no room for even one dirheader + name */ 827 return EINVAL; 828 } 829 830 /* how much to actually read */ 831 rawbufmax = callerbytes + skipstart - dropend; 832 833 /* read it */ 834 rawbuf = kmem_alloc(rawbufmax, KM_SLEEP); 835 rawiov.iov_base = rawbuf; 836 rawiov.iov_len = rawbufmax; 837 rawuio.uio_iov = &rawiov; 838 rawuio.uio_iovcnt = 1; 839 rawuio.uio_offset = physstart; 840 rawuio.uio_resid = rawbufmax; 841 UIO_SETUP_SYSSPACE(&rawuio); 842 rawuio.uio_rw = UIO_READ; 843 error = VOP_READ(vp, &rawuio, 0, ap->a_cred); 844 if (error != 0) { 845 kmem_free(rawbuf, rawbufmax); 846 return error; 847 } 848 rawbytes = rawbufmax - rawuio.uio_resid; 849 850 /* the raw entries to iterate over */ 851 rawdp = (LFS_DIRHEADER *)(void *)rawbuf; 852 stoprawdp = (LFS_DIRHEADER *)(void *)&rawbuf[rawbytes]; 853 854 /* allocate space to produce dirents into */ 855 direntbufmax = callerbytes; 856 direntbuf = kmem_alloc(direntbufmax, KM_SLEEP); 857 858 /* the dirents to iterate over */ 859 dirent = (struct dirent *)(void *)direntbuf; 860 stopdirent = (struct dirent *)(void *)&direntbuf[direntbufmax]; 861 862 /* the output "cookies" (seek positions of directory entries) */ 863 if (ap->a_cookies) { 864 numcookies = 0; 865 maxcookies = rawbytes / LFS_DIRECTSIZ(fs, 1); 866 cookies = malloc(maxcookies * sizeof(*cookies), 867 M_TEMP, M_WAITOK); 868 } else { 869 /* XXX: GCC */ 870 maxcookies = 0; 871 cookies = NULL; 872 } 873 874 /* now produce the dirents */ 875 curoffset = calleruio->uio_offset; 876 while (rawdp < stoprawdp) { 877 if (skipstart > 0) { 878 /* drain skipstart */ 879 if (lfs_dir_getreclen(fs, rawdp) <= skipstart) { 880 skipstart -= lfs_dir_getreclen(fs, rawdp); 881 rawdp = LFS_NEXTDIR(fs, rawdp); 882 continue; 883 } 884 /* caller's start position wasn't on an entry */ 885 error = EINVAL; 886 goto out; 887 } 888 if (lfs_dir_getreclen(fs, rawdp) == 0) { 889 struct dirent *save = dirent; 890 dirent->d_reclen = _DIRENT_MINSIZE(dirent); 891 dirent = _DIRENT_NEXT(dirent); 892 save->d_reclen = 0; 893 rawdp = stoprawdp; 894 break; 895 } 896 897 /* copy the header */ 898 dirent->d_type = lfs_dir_gettype(fs, rawdp); 899 dirent->d_namlen = lfs_dir_getnamlen(fs, rawdp); 900 dirent->d_reclen = _DIRENT_RECLEN(dirent, dirent->d_namlen); 901 902 /* stop if there isn't room for the name AND another header */ 903 if ((char *)(void *)dirent + dirent->d_reclen + 904 _DIRENT_MINSIZE(dirent) > (char *)(void *)stopdirent) 905 break; 906 907 /* copy the name (and inode (XXX: why after the test?)) */ 908 dirent->d_fileno = lfs_dir_getino(fs, rawdp); 909 (void)memcpy(dirent->d_name, lfs_dir_nameptr(fs, rawdp), 910 dirent->d_namlen); 911 memset(&dirent->d_name[dirent->d_namlen], 0, 912 dirent->d_reclen - _DIRENT_NAMEOFF(dirent) 913 - dirent->d_namlen); 914 915 /* onward */ 916 curoffset += lfs_dir_getreclen(fs, rawdp); 917 if (ap->a_cookies) { 918 KASSERT(numcookies < maxcookies); 919 cookies[numcookies++] = curoffset; 920 } 921 dirent = _DIRENT_NEXT(dirent); 922 rawdp = LFS_NEXTDIR(fs, rawdp); 923 } 924 925 /* transfer the dirents to the caller's buffer */ 926 callerbytes = ((char *)(void *)dirent - direntbuf); 927 error = uiomove(direntbuf, callerbytes, calleruio); 928 929 out: 930 calleruio->uio_offset = curoffset; 931 if (ap->a_cookies) { 932 if (error) { 933 free(cookies, M_TEMP); 934 *ap->a_cookies = NULL; 935 *ap->a_ncookies = 0; 936 } else { 937 *ap->a_cookies = cookies; 938 *ap->a_ncookies = numcookies; 939 } 940 } 941 kmem_free(direntbuf, direntbufmax); 942 kmem_free(rawbuf, rawbufmax); 943 *ap->a_eofflag = VTOI(vp)->i_size <= calleruio->uio_offset; 944 return error; 945 } 946 947 /* 948 * Return target name of a symbolic link 949 */ 950 int 951 ulfs_readlink(void *v) 952 { 953 struct vop_readlink_args /* { 954 struct vnode *a_vp; 955 struct uio *a_uio; 956 kauth_cred_t a_cred; 957 } */ *ap = v; 958 struct vnode *vp = ap->a_vp; 959 struct inode *ip = VTOI(vp); 960 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 961 struct lfs *fs = ump->um_lfs; 962 int isize; 963 964 KASSERT(VOP_ISLOCKED(vp)); 965 966 /* 967 * The test against um_maxsymlinklen is off by one; it should 968 * theoretically be <=, not <. However, it cannot be changed 969 * as that would break compatibility with existing fs images. 970 */ 971 972 isize = ip->i_size; 973 if (isize < fs->um_maxsymlinklen || 974 (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) { 975 uiomove((char *)SHORTLINK(ip), isize, ap->a_uio); 976 return (0); 977 } 978 return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred)); 979 } 980 981 /* 982 * Print out the contents of an inode. 983 */ 984 int 985 ulfs_print(void *v) 986 { 987 struct vop_print_args /* { 988 struct vnode *a_vp; 989 } */ *ap = v; 990 struct vnode *vp; 991 struct inode *ip; 992 993 vp = ap->a_vp; 994 ip = VTOI(vp); 995 printf("tag VT_ULFS, ino %llu, on dev %llu, %llu", 996 (unsigned long long)ip->i_number, 997 (unsigned long long)major(ip->i_dev), 998 (unsigned long long)minor(ip->i_dev)); 999 printf(" flags 0x%x, nlink %d\n", 1000 ip->i_state, ip->i_nlink); 1001 printf("\tmode 0%o, owner %d, group %d, size %qd", 1002 ip->i_mode, ip->i_uid, ip->i_gid, 1003 (long long)ip->i_size); 1004 if (vp->v_type == VFIFO) 1005 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 1006 printf("\n"); 1007 return (0); 1008 } 1009 1010 /* 1011 * Read wrapper for special devices. 1012 */ 1013 int 1014 ulfsspec_read(void *v) 1015 { 1016 struct vop_read_args /* { 1017 struct vnode *a_vp; 1018 struct uio *a_uio; 1019 int a_ioflag; 1020 kauth_cred_t a_cred; 1021 } */ *ap = v; 1022 1023 KASSERT(VOP_ISLOCKED(ap->a_vp)); 1024 1025 /* 1026 * Set access flag. 1027 */ 1028 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1029 VTOI(ap->a_vp)->i_state |= IN_ACCESS; 1030 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); 1031 } 1032 1033 /* 1034 * Write wrapper for special devices. 1035 */ 1036 int 1037 ulfsspec_write(void *v) 1038 { 1039 struct vop_write_args /* { 1040 struct vnode *a_vp; 1041 struct uio *a_uio; 1042 int a_ioflag; 1043 kauth_cred_t a_cred; 1044 } */ *ap = v; 1045 1046 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 1047 1048 /* 1049 * Set update and change flags. 1050 */ 1051 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1052 VTOI(ap->a_vp)->i_state |= IN_MODIFY; 1053 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); 1054 } 1055 1056 /* 1057 * Read wrapper for fifo's 1058 */ 1059 int 1060 ulfsfifo_read(void *v) 1061 { 1062 struct vop_read_args /* { 1063 struct vnode *a_vp; 1064 struct uio *a_uio; 1065 int a_ioflag; 1066 kauth_cred_t a_cred; 1067 } */ *ap = v; 1068 1069 KASSERT(VOP_ISLOCKED(ap->a_vp)); 1070 1071 /* 1072 * Set access flag. 1073 */ 1074 VTOI(ap->a_vp)->i_state |= IN_ACCESS; 1075 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); 1076 } 1077 1078 /* 1079 * Write wrapper for fifo's. 1080 */ 1081 int 1082 ulfsfifo_write(void *v) 1083 { 1084 struct vop_write_args /* { 1085 struct vnode *a_vp; 1086 struct uio *a_uio; 1087 int a_ioflag; 1088 kauth_cred_t a_cred; 1089 } */ *ap = v; 1090 1091 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 1092 1093 /* 1094 * Set update and change flags. 1095 */ 1096 VTOI(ap->a_vp)->i_state |= IN_MODIFY; 1097 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); 1098 } 1099 1100 /* 1101 * Return POSIX pathconf information applicable to ulfs filesystems. 1102 */ 1103 int 1104 ulfs_pathconf(void *v) 1105 { 1106 struct vop_pathconf_args /* { 1107 struct vnode *a_vp; 1108 int a_name; 1109 register_t *a_retval; 1110 } */ *ap = v; 1111 1112 switch (ap->a_name) { 1113 case _PC_LINK_MAX: 1114 *ap->a_retval = LINK_MAX; 1115 return (0); 1116 case _PC_NAME_MAX: 1117 *ap->a_retval = LFS_MAXNAMLEN; 1118 return (0); 1119 case _PC_PATH_MAX: 1120 *ap->a_retval = PATH_MAX; 1121 return (0); 1122 case _PC_PIPE_BUF: 1123 *ap->a_retval = PIPE_BUF; 1124 return (0); 1125 case _PC_CHOWN_RESTRICTED: 1126 *ap->a_retval = 1; 1127 return (0); 1128 case _PC_NO_TRUNC: 1129 *ap->a_retval = 1; 1130 return (0); 1131 case _PC_SYNC_IO: 1132 *ap->a_retval = 1; 1133 return (0); 1134 case _PC_FILESIZEBITS: 1135 *ap->a_retval = 42; 1136 return (0); 1137 case _PC_SYMLINK_MAX: 1138 *ap->a_retval = MAXPATHLEN; 1139 return (0); 1140 case _PC_2_SYMLINKS: 1141 *ap->a_retval = 1; 1142 return (0); 1143 default: 1144 return (EINVAL); 1145 } 1146 /* NOTREACHED */ 1147 } 1148 1149 /* 1150 * Advisory record locking support 1151 */ 1152 int 1153 ulfs_advlock(void *v) 1154 { 1155 struct vop_advlock_args /* { 1156 struct vnode *a_vp; 1157 void * a_id; 1158 int a_op; 1159 struct flock *a_fl; 1160 int a_flags; 1161 } */ *ap = v; 1162 struct inode *ip; 1163 1164 ip = VTOI(ap->a_vp); 1165 return lf_advlock(ap, &ip->i_lockf, ip->i_size); 1166 } 1167 1168 /* 1169 * Initialize the vnode associated with a new inode, handle aliased 1170 * vnodes. 1171 */ 1172 void 1173 ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *), 1174 struct vnode **vpp) 1175 { 1176 struct timeval tv; 1177 struct inode *ip; 1178 struct vnode *vp; 1179 dev_t rdev; 1180 struct ulfsmount *ump; 1181 1182 vp = *vpp; 1183 ip = VTOI(vp); 1184 switch(vp->v_type = IFTOVT(ip->i_mode)) { 1185 case VCHR: 1186 case VBLK: 1187 vp->v_op = specops; 1188 ump = ip->i_ump; 1189 // XXX clean this up 1190 if (ump->um_fstype == ULFS1) 1191 rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev, 1192 ULFS_MPNEEDSWAP(ump->um_lfs)); 1193 else 1194 rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev, 1195 ULFS_MPNEEDSWAP(ump->um_lfs)); 1196 spec_node_init(vp, rdev); 1197 break; 1198 case VFIFO: 1199 vp->v_op = fifoops; 1200 break; 1201 case VNON: 1202 case VBAD: 1203 case VSOCK: 1204 case VLNK: 1205 case VDIR: 1206 case VREG: 1207 break; 1208 } 1209 if (ip->i_number == ULFS_ROOTINO) 1210 vp->v_vflag |= VV_ROOT; 1211 /* 1212 * Initialize modrev times 1213 */ 1214 getmicrouptime(&tv); 1215 ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32 1216 | tv.tv_usec * 4294u; 1217 *vpp = vp; 1218 } 1219 1220 /* 1221 * Allocate len bytes at offset off. 1222 */ 1223 int 1224 ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 1225 kauth_cred_t cred) 1226 { 1227 struct inode *ip = VTOI(vp); 1228 int error, delta, bshift, bsize; 1229 UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist); 1230 1231 KASSERT(genfs_node_wrlocked(vp)); 1232 1233 error = 0; 1234 bshift = vp->v_mount->mnt_fs_bshift; 1235 bsize = 1 << bshift; 1236 1237 delta = off & (bsize - 1); 1238 off -= delta; 1239 len += delta; 1240 1241 while (len > 0) { 1242 bsize = MIN(bsize, len); 1243 1244 error = lfs_balloc(vp, off, bsize, cred, flags, NULL); 1245 if (error) { 1246 goto out; 1247 } 1248 1249 /* 1250 * increase file size now, lfs_balloc() requires that 1251 * EOF be up-to-date before each call. 1252 */ 1253 1254 if (ip->i_size < off + bsize) { 1255 UVMHIST_LOG(ubchist, "vp %#jx old 0x%jx new 0x%jx", 1256 (uintptr_t)vp, ip->i_size, off + bsize, 0); 1257 ip->i_size = off + bsize; 1258 DIP_ASSIGN(ip, size, ip->i_size); 1259 } 1260 1261 off += bsize; 1262 len -= bsize; 1263 } 1264 1265 out: 1266 return error; 1267 } 1268 1269 void 1270 ulfs_gop_markupdate(struct vnode *vp, int flags) 1271 { 1272 u_int32_t mask = 0; 1273 1274 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 1275 mask = IN_ACCESS; 1276 } 1277 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 1278 if (vp->v_type == VREG) { 1279 mask |= IN_CHANGE | IN_UPDATE; 1280 } else { 1281 mask |= IN_MODIFY; 1282 } 1283 } 1284 if (mask) { 1285 struct inode *ip = VTOI(vp); 1286 1287 ip->i_state |= mask; 1288 } 1289 } 1290 1291 int 1292 ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off, 1293 int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l) 1294 { 1295 struct iovec iov; 1296 struct uio uio; 1297 int error; 1298 1299 KASSERT(ISSET(ioflg, IO_NODELOCKED)); 1300 KASSERT(VOP_ISLOCKED(vp)); 1301 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1302 1303 iov.iov_base = buf; 1304 iov.iov_len = len; 1305 uio.uio_iov = &iov; 1306 uio.uio_iovcnt = 1; 1307 uio.uio_resid = len; 1308 uio.uio_offset = off; 1309 uio.uio_rw = rw; 1310 UIO_SETUP_SYSSPACE(&uio); 1311 1312 switch (rw) { 1313 case UIO_READ: 1314 error = lfs_bufrd(vp, &uio, ioflg, cred); 1315 break; 1316 case UIO_WRITE: 1317 error = lfs_bufwr(vp, &uio, ioflg, cred); 1318 break; 1319 default: 1320 panic("invalid uio rw: %d", (int)rw); 1321 } 1322 1323 if (aresid) 1324 *aresid = uio.uio_resid; 1325 else if (uio.uio_resid && error == 0) 1326 error = EIO; 1327 1328 KASSERT(VOP_ISLOCKED(vp)); 1329 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1330 return error; 1331 } 1332