1 /* $NetBSD: ulfs_vnops.c,v 1.54 2020/09/05 16:30:13 riastradh 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.54 2020/09/05 16:30:13 riastradh 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 VN_KNOTE(vp, NOTE_ATTRIB); 414 out: 415 return (error); 416 } 417 418 /* 419 * Change the mode on a file. 420 * Inode must be locked before calling. 421 */ 422 static int 423 ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) 424 { 425 struct inode *ip; 426 int error; 427 428 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 429 430 ip = VTOI(vp); 431 432 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 433 NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode)); 434 if (error) 435 return (error); 436 437 ip->i_mode &= ~ALLPERMS; 438 ip->i_mode |= (mode & ALLPERMS); 439 ip->i_state |= IN_CHANGE; 440 DIP_ASSIGN(ip, mode, ip->i_mode); 441 return (0); 442 } 443 444 /* 445 * Perform chown operation on inode ip; 446 * inode must be locked prior to call. 447 */ 448 static int 449 ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 450 struct lwp *l) 451 { 452 struct inode *ip; 453 int error = 0; 454 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 455 uid_t ouid; 456 gid_t ogid; 457 int64_t change; 458 #endif 459 460 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 461 462 ip = VTOI(vp); 463 error = 0; 464 465 if (uid == (uid_t)VNOVAL) 466 uid = ip->i_uid; 467 if (gid == (gid_t)VNOVAL) 468 gid = ip->i_gid; 469 470 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, 471 NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid)); 472 if (error) 473 return (error); 474 475 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 476 ogid = ip->i_gid; 477 ouid = ip->i_uid; 478 change = DIP(ip, blocks); 479 (void) lfs_chkdq(ip, -change, cred, 0); 480 (void) lfs_chkiq(ip, -1, cred, 0); 481 #endif 482 ip->i_gid = gid; 483 DIP_ASSIGN(ip, gid, gid); 484 ip->i_uid = uid; 485 DIP_ASSIGN(ip, uid, uid); 486 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 487 if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) { 488 if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0) 489 goto good; 490 else 491 (void) lfs_chkdq(ip, -change, cred, FORCE); 492 } 493 ip->i_gid = ogid; 494 DIP_ASSIGN(ip, gid, ogid); 495 ip->i_uid = ouid; 496 DIP_ASSIGN(ip, uid, ouid); 497 (void) lfs_chkdq(ip, change, cred, FORCE); 498 (void) lfs_chkiq(ip, 1, cred, FORCE); 499 return (error); 500 good: 501 #endif /* LFS_QUOTA || LFS_QUOTA2 */ 502 ip->i_state |= IN_CHANGE; 503 return (0); 504 } 505 506 int 507 ulfs_remove(void *v) 508 { 509 struct vop_remove_v2_args /* { 510 struct vnode *a_dvp; 511 struct vnode *a_vp; 512 struct componentname *a_cnp; 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 } 539 VN_KNOTE(vp, NOTE_DELETE); 540 VN_KNOTE(dvp, NOTE_WRITE); 541 if (dvp == vp) 542 vrele(vp); 543 else 544 vput(vp); 545 return (error); 546 } 547 548 /* 549 * ulfs_link: create hard link. 550 */ 551 int 552 ulfs_link(void *v) 553 { 554 struct vop_link_v2_args /* { 555 struct vnode *a_dvp; 556 struct vnode *a_vp; 557 struct componentname *a_cnp; 558 } */ *ap = v; 559 struct vnode *dvp = ap->a_dvp; 560 struct vnode *vp = ap->a_vp; 561 struct componentname *cnp = ap->a_cnp; 562 struct inode *ip; 563 int error; 564 struct ulfs_lookup_results *ulr; 565 566 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 567 KASSERT(dvp != vp); 568 KASSERT(vp->v_type != VDIR); 569 570 /* XXX should handle this material another way */ 571 ulr = &VTOI(dvp)->i_crap; 572 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 573 574 error = vn_lock(vp, LK_EXCLUSIVE); 575 if (error) { 576 VOP_ABORTOP(dvp, cnp); 577 goto out2; 578 } 579 if (vp->v_mount != dvp->v_mount) { 580 error = ENOENT; 581 VOP_ABORTOP(dvp, cnp); 582 goto out2; 583 } 584 ip = VTOI(vp); 585 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 586 VOP_ABORTOP(dvp, cnp); 587 error = EMLINK; 588 goto out1; 589 } 590 if (ip->i_flags & (IMMUTABLE | APPEND)) { 591 VOP_ABORTOP(dvp, cnp); 592 error = EPERM; 593 goto out1; 594 } 595 ip->i_nlink++; 596 DIP_ASSIGN(ip, nlink, ip->i_nlink); 597 ip->i_state |= IN_CHANGE; 598 error = lfs_update(vp, NULL, NULL, UPDATE_DIROP); 599 if (!error) { 600 error = ulfs_direnter(dvp, ulr, vp, 601 cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL); 602 } 603 if (error) { 604 ip->i_nlink--; 605 DIP_ASSIGN(ip, nlink, ip->i_nlink); 606 ip->i_state |= IN_CHANGE; 607 } 608 out1: 609 VOP_UNLOCK(vp); 610 out2: 611 VN_KNOTE(vp, NOTE_LINK); 612 VN_KNOTE(dvp, NOTE_WRITE); 613 return (error); 614 } 615 616 /* 617 * whiteout vnode call 618 */ 619 int 620 ulfs_whiteout(void *v) 621 { 622 struct vop_whiteout_args /* { 623 struct vnode *a_dvp; 624 struct componentname *a_cnp; 625 int a_flags; 626 } */ *ap = v; 627 struct vnode *dvp = ap->a_dvp; 628 struct componentname *cnp = ap->a_cnp; 629 int error; 630 struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); 631 struct lfs *fs = ump->um_lfs; 632 struct ulfs_lookup_results *ulr; 633 634 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 635 636 /* XXX should handle this material another way */ 637 ulr = &VTOI(dvp)->i_crap; 638 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 639 640 error = 0; 641 switch (ap->a_flags) { 642 case LOOKUP: 643 /* 4.4 format directories support whiteout operations */ 644 if (fs->um_maxsymlinklen > 0) 645 return (0); 646 return (EOPNOTSUPP); 647 648 case CREATE: 649 /* create a new directory whiteout */ 650 KASSERTMSG((fs->um_maxsymlinklen > 0), 651 "ulfs_whiteout: old format filesystem"); 652 653 error = ulfs_direnter(dvp, ulr, NULL, 654 cnp, ULFS_WINO, LFS_DT_WHT, NULL); 655 break; 656 657 case DELETE: 658 /* remove an existing directory whiteout */ 659 KASSERTMSG((fs->um_maxsymlinklen > 0), 660 "ulfs_whiteout: old format filesystem"); 661 662 cnp->cn_flags &= ~DOWHITEOUT; 663 error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0); 664 break; 665 default: 666 panic("ulfs_whiteout: unknown op"); 667 /* NOTREACHED */ 668 } 669 return (error); 670 } 671 672 int 673 ulfs_rmdir(void *v) 674 { 675 struct vop_rmdir_v2_args /* { 676 struct vnode *a_dvp; 677 struct vnode *a_vp; 678 struct componentname *a_cnp; 679 } */ *ap = v; 680 struct vnode *vp, *dvp; 681 struct componentname *cnp; 682 struct inode *ip, *dp; 683 int error; 684 struct ulfs_lookup_results *ulr; 685 686 dvp = ap->a_dvp; 687 vp = ap->a_vp; 688 cnp = ap->a_cnp; 689 690 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 691 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 692 693 dp = VTOI(dvp); 694 ip = VTOI(vp); 695 696 /* XXX should handle this material another way */ 697 ulr = &dp->i_crap; 698 ULFS_CHECK_CRAPCOUNTER(dp); 699 700 /* 701 * No rmdir "." or of mounted directories please. 702 */ 703 if (dp == ip || vp->v_mountedhere != NULL) { 704 if (dp == ip) 705 vrele(vp); 706 else 707 vput(vp); 708 return (EINVAL); 709 } 710 711 /* 712 * Do not remove a directory that is in the process of being renamed. 713 * Verify that the directory is empty (and valid). (Rmdir ".." won't 714 * be valid since ".." will contain a reference to the current 715 * directory and thus be non-empty.) 716 */ 717 error = 0; 718 if (ip->i_nlink != 2 || 719 !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 720 error = ENOTEMPTY; 721 goto out; 722 } 723 if ((dp->i_flags & APPEND) || 724 (ip->i_flags & (IMMUTABLE | APPEND))) { 725 error = EPERM; 726 goto out; 727 } 728 /* 729 * Delete reference to directory before purging 730 * inode. If we crash in between, the directory 731 * will be reattached to lost+found, 732 */ 733 error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1); 734 if (error) { 735 goto out; 736 } 737 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 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 VN_KNOTE(vp, NOTE_DELETE); 758 vput(vp); 759 return (error); 760 } 761 762 /* 763 * Vnode op for reading directories. 764 * 765 * This routine handles converting from the on-disk directory format 766 * "struct lfs_direct" to the in-memory format "struct dirent" as well as 767 * byte swapping the entries if necessary. 768 */ 769 int 770 ulfs_readdir(void *v) 771 { 772 struct vop_readdir_args /* { 773 struct vnode *a_vp; 774 struct uio *a_uio; 775 kauth_cred_t a_cred; 776 int *a_eofflag; 777 off_t **a_cookies; 778 int *a_ncookies; 779 } */ *ap = v; 780 781 /* vnode and fs */ 782 struct vnode *vp = ap->a_vp; 783 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 784 struct lfs *fs = ump->um_lfs; 785 /* caller's buffer */ 786 struct uio *calleruio = ap->a_uio; 787 off_t startoffset, endoffset; 788 size_t callerbytes; 789 off_t curoffset; 790 /* dirent production buffer */ 791 char *direntbuf; 792 size_t direntbufmax; 793 struct dirent *dirent, *stopdirent; 794 /* output cookies array */ 795 off_t *cookies; 796 size_t numcookies, maxcookies; 797 /* disk buffer */ 798 off_t physstart, physend; 799 size_t skipstart, dropend; 800 char *rawbuf; 801 size_t rawbufmax, rawbytes; 802 struct uio rawuio; 803 struct iovec rawiov; 804 LFS_DIRHEADER *rawdp, *stoprawdp; 805 /* general */ 806 int error; 807 808 KASSERT(VOP_ISLOCKED(vp)); 809 810 /* figure out where we want to read */ 811 callerbytes = calleruio->uio_resid; 812 startoffset = calleruio->uio_offset; 813 endoffset = startoffset + callerbytes; 814 815 if (callerbytes < _DIRENT_MINSIZE(dirent)) { 816 /* no room for even one struct dirent */ 817 return EINVAL; 818 } 819 820 /* round start and end down to block boundaries */ 821 physstart = startoffset & ~(off_t)(fs->um_dirblksiz - 1); 822 physend = endoffset & ~(off_t)(fs->um_dirblksiz - 1); 823 skipstart = startoffset - physstart; 824 dropend = endoffset - physend; 825 826 if (callerbytes - dropend < LFS_DIRECTSIZ(fs, 0)) { 827 /* no room for even one dirheader + name */ 828 return EINVAL; 829 } 830 831 /* how much to actually read */ 832 rawbufmax = callerbytes + skipstart - dropend; 833 834 /* read it */ 835 rawbuf = kmem_alloc(rawbufmax, KM_SLEEP); 836 rawiov.iov_base = rawbuf; 837 rawiov.iov_len = rawbufmax; 838 rawuio.uio_iov = &rawiov; 839 rawuio.uio_iovcnt = 1; 840 rawuio.uio_offset = physstart; 841 rawuio.uio_resid = rawbufmax; 842 UIO_SETUP_SYSSPACE(&rawuio); 843 rawuio.uio_rw = UIO_READ; 844 error = VOP_READ(vp, &rawuio, 0, ap->a_cred); 845 if (error != 0) { 846 kmem_free(rawbuf, rawbufmax); 847 return error; 848 } 849 rawbytes = rawbufmax - rawuio.uio_resid; 850 851 /* the raw entries to iterate over */ 852 rawdp = (LFS_DIRHEADER *)(void *)rawbuf; 853 stoprawdp = (LFS_DIRHEADER *)(void *)&rawbuf[rawbytes]; 854 855 /* allocate space to produce dirents into */ 856 direntbufmax = callerbytes; 857 direntbuf = kmem_alloc(direntbufmax, KM_SLEEP); 858 859 /* the dirents to iterate over */ 860 dirent = (struct dirent *)(void *)direntbuf; 861 stopdirent = (struct dirent *)(void *)&direntbuf[direntbufmax]; 862 863 /* the output "cookies" (seek positions of directory entries) */ 864 if (ap->a_cookies) { 865 numcookies = 0; 866 maxcookies = rawbytes / LFS_DIRECTSIZ(fs, 1); 867 cookies = malloc(maxcookies * sizeof(*cookies), 868 M_TEMP, M_WAITOK); 869 } else { 870 /* XXX: GCC */ 871 maxcookies = 0; 872 cookies = NULL; 873 } 874 875 /* now produce the dirents */ 876 curoffset = calleruio->uio_offset; 877 while (rawdp < stoprawdp) { 878 if (skipstart > 0) { 879 /* drain skipstart */ 880 if (lfs_dir_getreclen(fs, rawdp) <= skipstart) { 881 skipstart -= lfs_dir_getreclen(fs, rawdp); 882 rawdp = LFS_NEXTDIR(fs, rawdp); 883 continue; 884 } 885 /* caller's start position wasn't on an entry */ 886 error = EINVAL; 887 goto out; 888 } 889 if (lfs_dir_getreclen(fs, rawdp) == 0) { 890 struct dirent *save = dirent; 891 dirent->d_reclen = _DIRENT_MINSIZE(dirent); 892 dirent = _DIRENT_NEXT(dirent); 893 save->d_reclen = 0; 894 rawdp = stoprawdp; 895 break; 896 } 897 898 /* copy the header */ 899 dirent->d_type = lfs_dir_gettype(fs, rawdp); 900 dirent->d_namlen = lfs_dir_getnamlen(fs, rawdp); 901 dirent->d_reclen = _DIRENT_RECLEN(dirent, dirent->d_namlen); 902 903 /* stop if there isn't room for the name AND another header */ 904 if ((char *)(void *)dirent + dirent->d_reclen + 905 _DIRENT_MINSIZE(dirent) > (char *)(void *)stopdirent) 906 break; 907 908 /* copy the name (and inode (XXX: why after the test?)) */ 909 dirent->d_fileno = lfs_dir_getino(fs, rawdp); 910 (void)memcpy(dirent->d_name, lfs_dir_nameptr(fs, rawdp), 911 dirent->d_namlen); 912 memset(&dirent->d_name[dirent->d_namlen], 0, 913 dirent->d_reclen - _DIRENT_NAMEOFF(dirent) 914 - dirent->d_namlen); 915 916 /* onward */ 917 curoffset += lfs_dir_getreclen(fs, rawdp); 918 if (ap->a_cookies) { 919 KASSERT(numcookies < maxcookies); 920 cookies[numcookies++] = curoffset; 921 } 922 dirent = _DIRENT_NEXT(dirent); 923 rawdp = LFS_NEXTDIR(fs, rawdp); 924 } 925 926 /* transfer the dirents to the caller's buffer */ 927 callerbytes = ((char *)(void *)dirent - direntbuf); 928 error = uiomove(direntbuf, callerbytes, calleruio); 929 930 out: 931 calleruio->uio_offset = curoffset; 932 if (ap->a_cookies) { 933 if (error) { 934 free(cookies, M_TEMP); 935 *ap->a_cookies = NULL; 936 *ap->a_ncookies = 0; 937 } else { 938 *ap->a_cookies = cookies; 939 *ap->a_ncookies = numcookies; 940 } 941 } 942 kmem_free(direntbuf, direntbufmax); 943 kmem_free(rawbuf, rawbufmax); 944 *ap->a_eofflag = VTOI(vp)->i_size <= calleruio->uio_offset; 945 return error; 946 } 947 948 /* 949 * Return target name of a symbolic link 950 */ 951 int 952 ulfs_readlink(void *v) 953 { 954 struct vop_readlink_args /* { 955 struct vnode *a_vp; 956 struct uio *a_uio; 957 kauth_cred_t a_cred; 958 } */ *ap = v; 959 struct vnode *vp = ap->a_vp; 960 struct inode *ip = VTOI(vp); 961 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 962 struct lfs *fs = ump->um_lfs; 963 int isize; 964 965 KASSERT(VOP_ISLOCKED(vp)); 966 967 /* 968 * The test against um_maxsymlinklen is off by one; it should 969 * theoretically be <=, not <. However, it cannot be changed 970 * as that would break compatibility with existing fs images. 971 */ 972 973 isize = ip->i_size; 974 if (isize < fs->um_maxsymlinklen || 975 (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) { 976 uiomove((char *)SHORTLINK(ip), isize, ap->a_uio); 977 return (0); 978 } 979 return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred)); 980 } 981 982 /* 983 * Print out the contents of an inode. 984 */ 985 int 986 ulfs_print(void *v) 987 { 988 struct vop_print_args /* { 989 struct vnode *a_vp; 990 } */ *ap = v; 991 struct vnode *vp; 992 struct inode *ip; 993 994 vp = ap->a_vp; 995 ip = VTOI(vp); 996 printf("tag VT_ULFS, ino %llu, on dev %llu, %llu", 997 (unsigned long long)ip->i_number, 998 (unsigned long long)major(ip->i_dev), 999 (unsigned long long)minor(ip->i_dev)); 1000 printf(" flags 0x%x, nlink %d\n", 1001 ip->i_state, ip->i_nlink); 1002 printf("\tmode 0%o, owner %d, group %d, size %qd", 1003 ip->i_mode, ip->i_uid, ip->i_gid, 1004 (long long)ip->i_size); 1005 if (vp->v_type == VFIFO) 1006 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 1007 printf("\n"); 1008 return (0); 1009 } 1010 1011 /* 1012 * Read wrapper for special devices. 1013 */ 1014 int 1015 ulfsspec_read(void *v) 1016 { 1017 struct vop_read_args /* { 1018 struct vnode *a_vp; 1019 struct uio *a_uio; 1020 int a_ioflag; 1021 kauth_cred_t a_cred; 1022 } */ *ap = v; 1023 1024 KASSERT(VOP_ISLOCKED(ap->a_vp)); 1025 1026 /* 1027 * Set access flag. 1028 */ 1029 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1030 VTOI(ap->a_vp)->i_state |= IN_ACCESS; 1031 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); 1032 } 1033 1034 /* 1035 * Write wrapper for special devices. 1036 */ 1037 int 1038 ulfsspec_write(void *v) 1039 { 1040 struct vop_write_args /* { 1041 struct vnode *a_vp; 1042 struct uio *a_uio; 1043 int a_ioflag; 1044 kauth_cred_t a_cred; 1045 } */ *ap = v; 1046 1047 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 1048 1049 /* 1050 * Set update and change flags. 1051 */ 1052 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 1053 VTOI(ap->a_vp)->i_state |= IN_MODIFY; 1054 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); 1055 } 1056 1057 /* 1058 * Read wrapper for fifo's 1059 */ 1060 int 1061 ulfsfifo_read(void *v) 1062 { 1063 struct vop_read_args /* { 1064 struct vnode *a_vp; 1065 struct uio *a_uio; 1066 int a_ioflag; 1067 kauth_cred_t a_cred; 1068 } */ *ap = v; 1069 1070 KASSERT(VOP_ISLOCKED(ap->a_vp)); 1071 1072 /* 1073 * Set access flag. 1074 */ 1075 VTOI(ap->a_vp)->i_state |= IN_ACCESS; 1076 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); 1077 } 1078 1079 /* 1080 * Write wrapper for fifo's. 1081 */ 1082 int 1083 ulfsfifo_write(void *v) 1084 { 1085 struct vop_write_args /* { 1086 struct vnode *a_vp; 1087 struct uio *a_uio; 1088 int a_ioflag; 1089 kauth_cred_t a_cred; 1090 } */ *ap = v; 1091 1092 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 1093 1094 /* 1095 * Set update and change flags. 1096 */ 1097 VTOI(ap->a_vp)->i_state |= IN_MODIFY; 1098 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); 1099 } 1100 1101 /* 1102 * Return POSIX pathconf information applicable to ulfs filesystems. 1103 */ 1104 int 1105 ulfs_pathconf(void *v) 1106 { 1107 struct vop_pathconf_args /* { 1108 struct vnode *a_vp; 1109 int a_name; 1110 register_t *a_retval; 1111 } */ *ap = v; 1112 1113 switch (ap->a_name) { 1114 case _PC_LINK_MAX: 1115 *ap->a_retval = LINK_MAX; 1116 return (0); 1117 case _PC_NAME_MAX: 1118 *ap->a_retval = LFS_MAXNAMLEN; 1119 return (0); 1120 case _PC_PATH_MAX: 1121 *ap->a_retval = PATH_MAX; 1122 return (0); 1123 case _PC_PIPE_BUF: 1124 *ap->a_retval = PIPE_BUF; 1125 return (0); 1126 case _PC_CHOWN_RESTRICTED: 1127 *ap->a_retval = 1; 1128 return (0); 1129 case _PC_NO_TRUNC: 1130 *ap->a_retval = 1; 1131 return (0); 1132 case _PC_SYNC_IO: 1133 *ap->a_retval = 1; 1134 return (0); 1135 case _PC_FILESIZEBITS: 1136 *ap->a_retval = 42; 1137 return (0); 1138 case _PC_SYMLINK_MAX: 1139 *ap->a_retval = MAXPATHLEN; 1140 return (0); 1141 case _PC_2_SYMLINKS: 1142 *ap->a_retval = 1; 1143 return (0); 1144 default: 1145 return (EINVAL); 1146 } 1147 /* NOTREACHED */ 1148 } 1149 1150 /* 1151 * Advisory record locking support 1152 */ 1153 int 1154 ulfs_advlock(void *v) 1155 { 1156 struct vop_advlock_args /* { 1157 struct vnode *a_vp; 1158 void * a_id; 1159 int a_op; 1160 struct flock *a_fl; 1161 int a_flags; 1162 } */ *ap = v; 1163 struct inode *ip; 1164 1165 ip = VTOI(ap->a_vp); 1166 return lf_advlock(ap, &ip->i_lockf, ip->i_size); 1167 } 1168 1169 /* 1170 * Initialize the vnode associated with a new inode, handle aliased 1171 * vnodes. 1172 */ 1173 void 1174 ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *), 1175 struct vnode **vpp) 1176 { 1177 struct timeval tv; 1178 struct inode *ip; 1179 struct vnode *vp; 1180 dev_t rdev; 1181 struct ulfsmount *ump; 1182 1183 vp = *vpp; 1184 ip = VTOI(vp); 1185 switch(vp->v_type = IFTOVT(ip->i_mode)) { 1186 case VCHR: 1187 case VBLK: 1188 vp->v_op = specops; 1189 ump = ip->i_ump; 1190 // XXX clean this up 1191 if (ump->um_fstype == ULFS1) 1192 rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev, 1193 ULFS_MPNEEDSWAP(ump->um_lfs)); 1194 else 1195 rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev, 1196 ULFS_MPNEEDSWAP(ump->um_lfs)); 1197 spec_node_init(vp, rdev); 1198 break; 1199 case VFIFO: 1200 vp->v_op = fifoops; 1201 break; 1202 case VNON: 1203 case VBAD: 1204 case VSOCK: 1205 case VLNK: 1206 case VDIR: 1207 case VREG: 1208 break; 1209 } 1210 if (ip->i_number == ULFS_ROOTINO) 1211 vp->v_vflag |= VV_ROOT; 1212 /* 1213 * Initialize modrev times 1214 */ 1215 getmicrouptime(&tv); 1216 ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32 1217 | tv.tv_usec * 4294u; 1218 *vpp = vp; 1219 } 1220 1221 /* 1222 * Allocate len bytes at offset off. 1223 */ 1224 int 1225 ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 1226 kauth_cred_t cred) 1227 { 1228 struct inode *ip = VTOI(vp); 1229 int error, delta, bshift, bsize; 1230 UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist); 1231 1232 KASSERT(genfs_node_wrlocked(vp)); 1233 1234 error = 0; 1235 bshift = vp->v_mount->mnt_fs_bshift; 1236 bsize = 1 << bshift; 1237 1238 delta = off & (bsize - 1); 1239 off -= delta; 1240 len += delta; 1241 1242 while (len > 0) { 1243 bsize = MIN(bsize, len); 1244 1245 error = lfs_balloc(vp, off, bsize, cred, flags, NULL); 1246 if (error) { 1247 goto out; 1248 } 1249 1250 /* 1251 * increase file size now, lfs_balloc() requires that 1252 * EOF be up-to-date before each call. 1253 */ 1254 1255 if (ip->i_size < off + bsize) { 1256 UVMHIST_LOG(ubchist, "vp %#jx old 0x%jx new 0x%jx", 1257 (uintptr_t)vp, ip->i_size, off + bsize, 0); 1258 ip->i_size = off + bsize; 1259 DIP_ASSIGN(ip, size, ip->i_size); 1260 } 1261 1262 off += bsize; 1263 len -= bsize; 1264 } 1265 1266 out: 1267 return error; 1268 } 1269 1270 void 1271 ulfs_gop_markupdate(struct vnode *vp, int flags) 1272 { 1273 u_int32_t mask = 0; 1274 1275 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 1276 mask = IN_ACCESS; 1277 } 1278 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 1279 if (vp->v_type == VREG) { 1280 mask |= IN_CHANGE | IN_UPDATE; 1281 } else { 1282 mask |= IN_MODIFY; 1283 } 1284 } 1285 if (mask) { 1286 struct inode *ip = VTOI(vp); 1287 1288 ip->i_state |= mask; 1289 } 1290 } 1291 1292 int 1293 ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off, 1294 int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l) 1295 { 1296 struct iovec iov; 1297 struct uio uio; 1298 int error; 1299 1300 KASSERT(ISSET(ioflg, IO_NODELOCKED)); 1301 KASSERT(VOP_ISLOCKED(vp)); 1302 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1303 1304 iov.iov_base = buf; 1305 iov.iov_len = len; 1306 uio.uio_iov = &iov; 1307 uio.uio_iovcnt = 1; 1308 uio.uio_resid = len; 1309 uio.uio_offset = off; 1310 uio.uio_rw = rw; 1311 UIO_SETUP_SYSSPACE(&uio); 1312 1313 switch (rw) { 1314 case UIO_READ: 1315 error = lfs_bufrd(vp, &uio, ioflg, cred); 1316 break; 1317 case UIO_WRITE: 1318 error = lfs_bufwr(vp, &uio, ioflg, cred); 1319 break; 1320 default: 1321 panic("invalid uio rw: %d", (int)rw); 1322 } 1323 1324 if (aresid) 1325 *aresid = uio.uio_resid; 1326 else if (uio.uio_resid && error == 0) 1327 error = EIO; 1328 1329 KASSERT(VOP_ISLOCKED(vp)); 1330 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1331 return error; 1332 } 1333