1 /* $NetBSD: efs_vnops.c,v 1.31 2014/02/07 15:29:21 hannken Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Stephen M. Rumble <rumble@ephemeral.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 __KERNEL_RCSID(0, "$NetBSD: efs_vnops.c,v 1.31 2014/02/07 15:29:21 hannken Exp $"); 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/proc.h> 25 #include <sys/kernel.h> 26 #include <sys/vnode.h> 27 #include <sys/mount.h> 28 #include <sys/malloc.h> 29 #include <sys/namei.h> 30 #include <sys/dirent.h> 31 #include <sys/lockf.h> 32 #include <sys/unistd.h> 33 #include <sys/buf.h> 34 35 #include <miscfs/genfs/genfs.h> 36 #include <miscfs/genfs/genfs_node.h> 37 #include <miscfs/fifofs/fifo.h> 38 #include <miscfs/specfs/specdev.h> 39 40 #include <fs/efs/efs.h> 41 #include <fs/efs/efs_sb.h> 42 #include <fs/efs/efs_dir.h> 43 #include <fs/efs/efs_genfs.h> 44 #include <fs/efs/efs_mount.h> 45 #include <fs/efs/efs_extent.h> 46 #include <fs/efs/efs_dinode.h> 47 #include <fs/efs/efs_inode.h> 48 #include <fs/efs/efs_subr.h> 49 #include <fs/efs/efs_ihash.h> 50 51 MALLOC_DECLARE(M_EFSTMP); 52 53 /* 54 * Lookup a pathname component in the given directory. 55 * 56 * Returns 0 on success. 57 */ 58 static int 59 efs_lookup(void *v) 60 { 61 struct vop_lookup_v2_args /* { 62 struct vnode *a_dvp; 63 struct vnode **a_vpp; 64 struct componentname *a_cnp; 65 } */ *ap = v; 66 struct componentname *cnp = ap->a_cnp; 67 struct vnode *vp; 68 ino_t ino; 69 int err, nameiop = cnp->cn_nameiop; 70 71 /* ensure that the directory can be accessed first */ 72 err = VOP_ACCESS(ap->a_dvp, VEXEC, cnp->cn_cred); 73 if (err) 74 return (err); 75 76 if (cache_lookup(ap->a_dvp, cnp->cn_nameptr, cnp->cn_namelen, 77 cnp->cn_nameiop, cnp->cn_flags, NULL, ap->a_vpp)) { 78 return *ap->a_vpp == NULLVP ? ENOENT : 0; 79 } 80 81 /* 82 * Handle the three lookup types: '.', '..', and everything else. 83 */ 84 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 85 vref(ap->a_dvp); 86 *ap->a_vpp = ap->a_dvp; 87 } else if (cnp->cn_flags & ISDOTDOT) { 88 err = efs_inode_lookup(VFSTOEFS(ap->a_dvp->v_mount), 89 EFS_VTOI(ap->a_dvp), ap->a_cnp, &ino); 90 if (err) 91 return (err); 92 93 VOP_UNLOCK(ap->a_dvp); /* preserve lock order */ 94 95 err = VFS_VGET(ap->a_dvp->v_mount, ino, &vp); 96 if (err) { 97 vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY); 98 return (err); 99 } 100 vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY); 101 *ap->a_vpp = vp; 102 } else { 103 err = efs_inode_lookup(VFSTOEFS(ap->a_dvp->v_mount), 104 EFS_VTOI(ap->a_dvp), ap->a_cnp, &ino); 105 if (err) { 106 if (err == ENOENT && nameiop != CREATE) 107 cache_enter(ap->a_dvp, NULL, cnp->cn_nameptr, 108 cnp->cn_namelen, cnp->cn_flags); 109 if (err == ENOENT && (nameiop == CREATE || 110 nameiop == RENAME)) { 111 err = VOP_ACCESS(ap->a_dvp, VWRITE, 112 cnp->cn_cred); 113 if (err) 114 return (err); 115 return (EJUSTRETURN); 116 } 117 return (err); 118 } 119 err = VFS_VGET(ap->a_dvp->v_mount, ino, &vp); 120 if (err) 121 return (err); 122 *ap->a_vpp = vp; 123 } 124 125 cache_enter(ap->a_dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, 126 cnp->cn_flags); 127 128 if (*ap->a_vpp != ap->a_dvp) 129 VOP_UNLOCK(*ap->a_vpp); 130 131 return 0; 132 } 133 134 static int 135 efs_check_possible(struct vnode *vp, struct efs_inode *eip, mode_t mode) 136 { 137 138 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 139 return (EROFS); 140 141 return 0; 142 } 143 144 /* 145 * Determine the accessiblity of a file based on the permissions allowed by the 146 * specified credentials. 147 * 148 * Returns 0 on success. 149 */ 150 static int 151 efs_check_permitted(struct vnode *vp, struct efs_inode *eip, mode_t mode, 152 kauth_cred_t cred) 153 { 154 155 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, 156 vp->v_type, eip->ei_mode), vp, NULL, genfs_can_access(vp->v_type, 157 eip->ei_mode, eip->ei_uid, eip->ei_gid, mode, cred)); 158 } 159 160 static int 161 efs_access(void *v) 162 { 163 struct vop_access_args /* { 164 const struct vnodeop_desc *a_desc; 165 struct vnode *a_vp; 166 int a_mode; 167 struct ucred *a_cred; 168 } */ *ap = v; 169 struct vnode *vp = ap->a_vp; 170 struct efs_inode *eip = EFS_VTOI(vp); 171 int error; 172 173 error = efs_check_possible(vp, eip, ap->a_mode); 174 if (error) 175 return error; 176 177 error = efs_check_permitted(vp, eip, ap->a_mode, ap->a_cred); 178 179 return error; 180 } 181 182 /* 183 * Get specific vnode attributes on a file. See vattr(9). 184 * 185 * Returns 0 on success. 186 */ 187 static int 188 efs_getattr(void *v) 189 { 190 struct vop_getattr_args /* { 191 const struct vnodeop_desc *a_desc; 192 struct vnode *a_vp; 193 struct vattr *a_vap; 194 struct ucred *a_cred; 195 } */ *ap = v; 196 197 struct vattr *vap = ap->a_vap; 198 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 199 200 vattr_null(ap->a_vap); 201 vap->va_type = ap->a_vp->v_type; 202 vap->va_mode = eip->ei_mode; 203 vap->va_nlink = eip->ei_nlink; 204 vap->va_uid = eip->ei_uid; 205 vap->va_gid = eip->ei_gid; 206 vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 207 vap->va_fileid = eip->ei_number; 208 vap->va_size = eip->ei_size; 209 210 if (ap->a_vp->v_type == VBLK) 211 vap->va_blocksize = BLKDEV_IOSIZE; 212 else if (ap->a_vp->v_type == VCHR) 213 vap->va_blocksize = MAXBSIZE; 214 else 215 vap->va_blocksize = EFS_BB_SIZE; 216 217 vap->va_atime.tv_sec = eip->ei_atime; 218 vap->va_mtime.tv_sec = eip->ei_mtime; 219 vap->va_ctime.tv_sec = eip->ei_ctime; 220 /* vap->va_birthtime = */ 221 vap->va_gen = eip->ei_gen; 222 vap->va_flags = ap->a_vp->v_vflag | 223 ap->a_vp->v_iflag | ap->a_vp->v_uflag; 224 225 if (ap->a_vp->v_type == VBLK || ap->a_vp->v_type == VCHR) { 226 uint32_t dmaj, dmin; 227 228 if (be16toh(eip->ei_di.di_odev) != EFS_DINODE_ODEV_INVALID) { 229 dmaj = EFS_DINODE_ODEV_MAJ(be16toh(eip->ei_di.di_odev)); 230 dmin = EFS_DINODE_ODEV_MIN(be16toh(eip->ei_di.di_odev)); 231 } else { 232 dmaj = EFS_DINODE_NDEV_MAJ(be32toh(eip->ei_di.di_ndev)); 233 dmin = EFS_DINODE_NDEV_MIN(be32toh(eip->ei_di.di_ndev)); 234 } 235 236 vap->va_rdev = makedev(dmaj, dmin); 237 } 238 239 vap->va_bytes = eip->ei_size; 240 /* vap->va_filerev = */ 241 /* vap->va_vaflags = */ 242 243 return (0); 244 } 245 246 /* 247 * Read a file. 248 * 249 * Returns 0 on success. 250 */ 251 static int 252 efs_read(void *v) 253 { 254 struct vop_read_args /* { 255 const struct vnodeop_desc *a_desc; 256 struct vnode *a_vp; 257 struct uio *a_uio; 258 int a_ioflag; 259 struct ucred *a_cred; 260 } */ *ap = v; 261 struct efs_extent ex; 262 struct efs_extent_iterator exi; 263 struct uio *uio = ap->a_uio; 264 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 265 off_t start; 266 vsize_t len; 267 int err, ret; 268 const int advice = IO_ADV_DECODE(ap->a_ioflag); 269 270 if (ap->a_vp->v_type == VDIR) 271 return (EISDIR); 272 273 if (ap->a_vp->v_type != VREG) 274 return (EINVAL); 275 276 efs_extent_iterator_init(&exi, eip, uio->uio_offset); 277 ret = efs_extent_iterator_next(&exi, &ex); 278 while (ret == 0) { 279 if (uio->uio_offset < 0 || uio->uio_offset >= eip->ei_size || 280 uio->uio_resid == 0) 281 break; 282 283 start = ex.ex_offset * EFS_BB_SIZE; 284 len = ex.ex_length * EFS_BB_SIZE; 285 286 if (!(uio->uio_offset >= start && 287 uio->uio_offset < (start + len))) { 288 ret = efs_extent_iterator_next(&exi, &ex); 289 continue; 290 } 291 292 start = uio->uio_offset - start; 293 294 len = MIN(len - start, uio->uio_resid); 295 len = MIN(len, eip->ei_size - uio->uio_offset); 296 297 err = ubc_uiomove(&ap->a_vp->v_uobj, uio, len, advice, 298 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(ap->a_vp)); 299 if (err) { 300 EFS_DPRINTF(("efs_read: uiomove error %d\n", 301 err)); 302 return (err); 303 } 304 } 305 306 return ((ret == -1) ? 0 : ret); 307 } 308 309 static int 310 efs_readdir(void *v) 311 { 312 struct vop_readdir_args /* { 313 const struct vnodeop_desc *a_desc; 314 struct vnode *a_vp; 315 struct uio *a_uio; 316 struct ucred *a_cred; 317 int *a_eofflag; 318 off_t **a_cookies; 319 int *a_ncookies; 320 } */ *ap = v; 321 struct dirent *dp; 322 struct efs_dinode edi; 323 struct efs_extent ex; 324 struct efs_extent_iterator exi; 325 struct buf *bp; 326 struct efs_dirent *de; 327 struct efs_dirblk *db; 328 struct uio *uio = ap->a_uio; 329 struct efs_inode *ei = EFS_VTOI(ap->a_vp); 330 off_t *cookies = NULL; 331 off_t offset; 332 int i, j, err, ret, s, slot, ncookies, maxcookies = 0; 333 334 if (ap->a_vp->v_type != VDIR) 335 return (ENOTDIR); 336 337 if (ap->a_eofflag != NULL) 338 *ap->a_eofflag = false; 339 340 if (ap->a_ncookies != NULL) { 341 ncookies = 0; 342 maxcookies = 343 uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); 344 cookies = malloc(maxcookies * sizeof(off_t), M_TEMP, M_WAITOK); 345 } 346 347 dp = malloc(sizeof(struct dirent), M_EFSTMP, M_WAITOK | M_ZERO); 348 349 offset = 0; 350 efs_extent_iterator_init(&exi, ei, 0); 351 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 352 for (i = 0; i < ex.ex_length; i++) { 353 err = efs_bread(VFSTOEFS(ap->a_vp->v_mount), 354 ex.ex_bn + i, NULL, &bp); 355 if (err) { 356 goto exit_err; 357 } 358 359 db = (struct efs_dirblk *)bp->b_data; 360 361 if (be16toh(db->db_magic) != EFS_DIRBLK_MAGIC) { 362 printf("efs_readdir: bad dirblk\n"); 363 brelse(bp, 0); 364 continue; 365 } 366 367 for (j = 0; j < db->db_slots; j++) { 368 slot = EFS_DIRENT_OFF_EXPND(db->db_space[j]); 369 if (slot == EFS_DIRBLK_SLOT_FREE) 370 continue; 371 372 if (!EFS_DIRENT_OFF_VALID(slot)) { 373 printf("efs_readdir: bad dirent\n"); 374 continue; 375 } 376 377 de = EFS_DIRBLK_TO_DIRENT(db, slot); 378 s = _DIRENT_RECLEN(dp, de->de_namelen); 379 380 if (offset < uio->uio_offset) { 381 offset += s; 382 continue; 383 } 384 385 /* XXX - shouldn't happen, right? */ 386 if (offset > uio->uio_offset || 387 s > uio->uio_resid) { 388 brelse(bp, 0); 389 goto exit_ok; 390 } 391 392 /* de_namelen is uint8_t, d.d_name is 512b */ 393 KASSERT(sizeof(dp->d_name)-de->de_namelen > 0); 394 dp->d_fileno = be32toh(de->de_inumber); 395 dp->d_reclen = s; 396 dp->d_namlen = de->de_namelen; 397 memcpy(dp->d_name, de->de_name, 398 de->de_namelen); 399 dp->d_name[de->de_namelen] = '\0'; 400 401 /* look up inode to get type */ 402 err = efs_read_inode( 403 VFSTOEFS(ap->a_vp->v_mount), 404 dp->d_fileno, NULL, &edi); 405 if (err) { 406 brelse(bp, 0); 407 goto exit_err; 408 } 409 410 switch (be16toh(edi.di_mode) & EFS_IFMT) { 411 case EFS_IFIFO: 412 dp->d_type = DT_FIFO; 413 break; 414 case EFS_IFCHR: 415 dp->d_type = DT_CHR; 416 break; 417 case EFS_IFDIR: 418 dp->d_type = DT_DIR; 419 break; 420 case EFS_IFBLK: 421 dp->d_type = DT_BLK; 422 break; 423 case EFS_IFREG: 424 dp->d_type = DT_REG; 425 break; 426 case EFS_IFLNK: 427 dp->d_type = DT_LNK; 428 break; 429 case EFS_IFSOCK: 430 dp->d_type = DT_SOCK; 431 break; 432 default: 433 dp->d_type = DT_UNKNOWN; 434 break; 435 } 436 437 err = uiomove(dp, s, uio); 438 if (err) { 439 brelse(bp, 0); 440 goto exit_err; 441 } 442 443 offset += s; 444 445 if (cookies != NULL && maxcookies != 0) { 446 cookies[ncookies++] = offset; 447 if (ncookies == maxcookies) { 448 brelse(bp, 0); 449 goto exit_ok; 450 } 451 } 452 } 453 454 brelse(bp, 0); 455 } 456 } 457 458 if (ret != -1) { 459 err = ret; 460 goto exit_err; 461 } 462 463 if (ap->a_eofflag != NULL) 464 *ap->a_eofflag = true; 465 466 exit_ok: 467 if (cookies != NULL) { 468 *ap->a_cookies = cookies; 469 *ap->a_ncookies = ncookies; 470 } 471 472 uio->uio_offset = offset; 473 474 free(dp, M_EFSTMP); 475 476 return (0); 477 478 exit_err: 479 if (cookies != NULL) 480 free(cookies, M_TEMP); 481 482 free(dp, M_EFSTMP); 483 484 return (err); 485 } 486 487 static int 488 efs_readlink(void *v) 489 { 490 struct vop_readlink_args /* { 491 const struct vnodeop_desc *a_desc; 492 struct vnode *a_vp; 493 struct uio *a_uio; 494 struct ucred *a_cred; 495 } */ *ap = v; 496 struct uio *uio = ap->a_uio; 497 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 498 char *buf; 499 size_t len; 500 int err, i; 501 502 if ((eip->ei_mode & EFS_IFMT) != EFS_IFLNK) 503 return (EINVAL); 504 505 if (uio->uio_resid < 1) 506 return (EINVAL); 507 508 buf = malloc(eip->ei_size + 1, M_EFSTMP, M_ZERO | M_WAITOK); 509 510 /* symlinks are either inlined in the inode, or in extents */ 511 if (eip->ei_numextents == 0) { 512 if (eip->ei_size > sizeof(eip->ei_di.di_symlink)) { 513 EFS_DPRINTF(("efs_readlink: too big for inline\n")); 514 free(buf, M_EFSTMP); 515 return (EBADF); 516 } 517 518 memcpy(buf, eip->ei_di.di_symlink, eip->ei_size); 519 len = MIN(uio->uio_resid, eip->ei_size + 1); 520 } else { 521 struct efs_extent_iterator exi; 522 struct efs_extent ex; 523 struct buf *bp; 524 int resid, off, ret; 525 526 off = 0; 527 resid = eip->ei_size; 528 529 efs_extent_iterator_init(&exi, eip, 0); 530 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 531 for (i = 0; i < ex.ex_length; i++) { 532 err = efs_bread(VFSTOEFS(ap->a_vp->v_mount), 533 ex.ex_bn + i, NULL, &bp); 534 if (err) { 535 free(buf, M_EFSTMP); 536 return (err); 537 } 538 539 len = MIN(resid, bp->b_bcount); 540 memcpy(buf + off, bp->b_data, len); 541 brelse(bp, 0); 542 543 off += len; 544 resid -= len; 545 546 if (resid == 0) 547 break; 548 } 549 550 if (resid == 0) 551 break; 552 } 553 554 if (ret != 0 && ret != -1) { 555 free(buf, M_EFSTMP); 556 return (ret); 557 } 558 559 len = off + 1; 560 } 561 562 KASSERT(len >= 1 && len <= (eip->ei_size + 1)); 563 buf[len - 1] = '\0'; 564 err = uiomove(buf, len, uio); 565 free(buf, M_EFSTMP); 566 567 return (err); 568 } 569 570 /* 571 * Release an inactive vnode. The vnode _must_ be unlocked on return. 572 * It is either nolonger being used by the kernel, or an unmount is being 573 * forced. 574 * 575 * Returns 0 on success. 576 */ 577 static int 578 efs_inactive(void *v) 579 { 580 struct vop_inactive_args /* { 581 const struct vnodeop_desc *a_desc; 582 struct vnode *a_vp; 583 bool *a_recycle 584 } */ *ap = v; 585 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 586 587 *ap->a_recycle = (eip->ei_mode == 0); 588 VOP_UNLOCK(ap->a_vp); 589 590 return (0); 591 } 592 593 static int 594 efs_reclaim(void *v) 595 { 596 struct vop_reclaim_args /* { 597 const struct vnodeop_desc *a_desc; 598 struct vnode *a_vp; 599 } */ *ap = v; 600 struct vnode *vp = ap->a_vp; 601 602 efs_ihashrem(EFS_VTOI(vp)); 603 genfs_node_destroy(vp); 604 pool_put(&efs_inode_pool, vp->v_data); 605 vp->v_data = NULL; 606 607 return (0); 608 } 609 610 static int 611 efs_bmap(void *v) 612 { 613 struct vop_bmap_args /* { 614 const struct vnodeop_desc *a_desc; 615 struct vnode *a_vp; 616 daddr_t a_bn; 617 struct vnode **a_vpp; 618 daddr_t *a_bnp; 619 int *a_runp; 620 } */ *ap = v; 621 struct efs_extent ex; 622 struct efs_extent_iterator exi; 623 struct vnode *vp = ap->a_vp; 624 struct efs_inode *eip = EFS_VTOI(vp); 625 bool found; 626 int ret; 627 628 if (ap->a_vpp != NULL) 629 *ap->a_vpp = VFSTOEFS(vp->v_mount)->em_devvp; 630 631 found = false; 632 efs_extent_iterator_init(&exi, eip, ap->a_bn * EFS_BB_SIZE); 633 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 634 if (ap->a_bn >= ex.ex_offset && 635 ap->a_bn < (ex.ex_offset + ex.ex_length)) { 636 found = true; 637 break; 638 } 639 } 640 641 KASSERT(!found || (found && ret == 0)); 642 643 if (!found) { 644 EFS_DPRINTF(("efs_bmap: ap->a_bn not in extents\n")); 645 return ((ret == -1) ? EIO : ret); 646 } 647 648 if (ex.ex_magic != EFS_EXTENT_MAGIC) { 649 EFS_DPRINTF(("efs_bmap: exn.ex_magic != EFS_EXTENT_MAGIC\n")); 650 return (EIO); 651 } 652 653 if (ap->a_bn < ex.ex_offset) { 654 EFS_DPRINTF(("efs_bmap: ap->a_bn < exn.ex_offset\n")); 655 return (EIO); 656 } 657 658 KASSERT(ap->a_bn >= ex.ex_offset); 659 KASSERT(ex.ex_length > ap->a_bn - ex.ex_offset); 660 661 *ap->a_bnp = ex.ex_bn + (ap->a_bn - ex.ex_offset); 662 if (ap->a_runp != NULL) 663 *ap->a_runp = ex.ex_length - (ap->a_bn - ex.ex_offset) - 1; 664 665 return (0); 666 } 667 668 static int 669 efs_strategy(void *v) 670 { 671 struct vop_strategy_args /* { 672 const struct vnodeop_desc *a_desc; 673 struct vnode *a_vp; 674 struct buf *a_bp; 675 } */ *ap = v; 676 struct vnode *vp = ap->a_vp; 677 struct buf *bp = ap->a_bp; 678 int error; 679 680 if (vp == NULL) { 681 bp->b_error = EIO; 682 biodone(bp); 683 return (EIO); 684 } 685 686 if (bp->b_blkno == bp->b_lblkno) { 687 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 688 if (error) { 689 bp->b_error = error; 690 biodone(bp); 691 return (error); 692 } 693 if ((long)bp->b_blkno == -1) 694 clrbuf(bp); 695 } 696 697 if ((long)bp->b_blkno == -1) { 698 biodone(bp); 699 return (0); 700 } 701 702 return (VOP_STRATEGY(VFSTOEFS(vp->v_mount)->em_devvp, bp)); 703 } 704 705 static int 706 efs_print(void *v) 707 { 708 struct vop_print_args /* { 709 const struct vnodeop_desc *a_desc; 710 struct vnode *a_vp; 711 } */ *ap = v; 712 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 713 714 printf( "efs_inode (ino %lu):\n" 715 " ei_mode: %07o\n" 716 " ei_nlink: %d\n" 717 " ei_uid: %d\n" 718 " ei_gid: %d\n" 719 " ei_size: %d\n" 720 " ei_atime: %d\n" 721 " ei_mtime: %d\n" 722 " ei_ctime: %d\n" 723 " ei_gen: %d\n" 724 " ei_numextents: %d\n" 725 " ei_version: %d\n", 726 (unsigned long)eip->ei_number, 727 (unsigned int)eip->ei_mode, 728 eip->ei_nlink, 729 eip->ei_uid, 730 eip->ei_gid, 731 eip->ei_size, 732 (int32_t)eip->ei_atime, 733 (int32_t)eip->ei_mtime, 734 (int32_t)eip->ei_ctime, 735 eip->ei_gen, 736 eip->ei_numextents, 737 eip->ei_version); 738 739 return (0); 740 } 741 742 static int 743 efs_pathconf(void *v) 744 { 745 struct vop_pathconf_args /* { 746 const struct vnodeop_desc *a_desc; 747 struct vnode *a_vp; 748 int a_name; 749 register_t *a_retval; 750 } */ *ap = v; 751 752 /* IRIX 4 values */ 753 switch (ap->a_name) { 754 case _PC_LINK_MAX: 755 *ap->a_retval = 30000; 756 break; 757 case _PC_NAME_MAX: 758 *ap->a_retval = 255; 759 break; 760 case _PC_PATH_MAX: 761 *ap->a_retval = 1024; 762 break; 763 case _PC_NO_TRUNC: 764 *ap->a_retval = 1; 765 break; 766 case _PC_CHOWN_RESTRICTED: 767 *ap->a_retval = 1; 768 break; 769 case _PC_SYNC_IO: 770 *ap->a_retval = 1; 771 break; 772 case _PC_FILESIZEBITS: 773 *ap->a_retval = 32; 774 break; 775 default: 776 return (EINVAL); 777 } 778 779 return (0); 780 } 781 782 static int 783 efs_advlock(void *v) 784 { 785 struct vop_advlock_args /* { 786 const struct vnodeop_desc *a_desc; 787 struct vnode *a_vp; 788 void *a_id; 789 int a_op; 790 struct flock *a_fl; 791 int a_flags; 792 } */ *ap = v; 793 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 794 795 return (lf_advlock(ap, &eip->ei_lockf, eip->ei_size)); 796 } 797 798 /* Global vfs data structures for efs */ 799 int (**efs_vnodeop_p)(void *); 800 const struct vnodeopv_entry_desc efs_vnodeop_entries[] = { 801 { &vop_default_desc, vn_default_error}, /* error handler */ 802 { &vop_lookup_desc, efs_lookup }, /* lookup */ 803 { &vop_create_desc, genfs_eopnotsupp}, /* create */ 804 { &vop_mknod_desc, genfs_eopnotsupp}, /* mknod */ 805 { &vop_open_desc, genfs_nullop }, /* open */ 806 { &vop_close_desc, genfs_nullop }, /* close */ 807 { &vop_access_desc, efs_access }, /* access */ 808 { &vop_getattr_desc, efs_getattr }, /* getattr */ 809 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 810 { &vop_read_desc, efs_read }, /* read */ 811 { &vop_write_desc, genfs_eopnotsupp}, /* write */ 812 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ 813 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 814 { &vop_poll_desc, genfs_poll }, /* poll */ 815 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 816 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 817 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 818 { &vop_fsync_desc, genfs_eopnotsupp}, /* fsync */ 819 { &vop_seek_desc, genfs_seek }, /* seek */ 820 { &vop_remove_desc, genfs_eopnotsupp}, /* remove */ 821 { &vop_link_desc, genfs_eopnotsupp}, /* link */ 822 { &vop_rename_desc, genfs_eopnotsupp}, /* rename */ 823 { &vop_mkdir_desc, genfs_eopnotsupp}, /* mkdir */ 824 { &vop_rmdir_desc, genfs_eopnotsupp}, /* rmdir */ 825 { &vop_symlink_desc, genfs_eopnotsupp}, /* symlink */ 826 { &vop_readdir_desc, efs_readdir }, /* readdir */ 827 { &vop_readlink_desc, efs_readlink }, /* readlink */ 828 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 829 { &vop_inactive_desc, efs_inactive }, /* inactive */ 830 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 831 { &vop_lock_desc, genfs_lock, }, /* lock */ 832 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 833 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 834 { &vop_bmap_desc, efs_bmap }, /* bmap */ 835 { &vop_print_desc, efs_print }, /* print */ 836 { &vop_pathconf_desc, efs_pathconf }, /* pathconf */ 837 { &vop_advlock_desc, efs_advlock }, /* advlock */ 838 /* blkatoff */ 839 /* valloc */ 840 /* balloc */ 841 /* vfree */ 842 /* truncate */ 843 /* whiteout */ 844 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 845 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 846 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 847 { &vop_strategy_desc, efs_strategy }, /* strategy */ 848 { NULL, NULL } 849 }; 850 const struct vnodeopv_desc efs_vnodeop_opv_desc = { 851 &efs_vnodeop_p, 852 efs_vnodeop_entries 853 }; 854 855 int (**efs_specop_p)(void *); 856 const struct vnodeopv_entry_desc efs_specop_entries[] = { 857 { &vop_default_desc, vn_default_error}, /* error handler */ 858 { &vop_lookup_desc, spec_lookup }, /* lookup */ 859 { &vop_create_desc, spec_create }, /* create */ 860 { &vop_mknod_desc, spec_mknod }, /* mknod */ 861 { &vop_open_desc, spec_open }, /* open */ 862 { &vop_close_desc, spec_close }, /* close */ 863 { &vop_access_desc, efs_access }, /* access */ 864 { &vop_getattr_desc, efs_getattr }, /* getattr */ 865 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 866 { &vop_read_desc, spec_read }, /* read */ 867 { &vop_write_desc, spec_write }, /* write */ 868 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 869 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 870 { &vop_poll_desc, spec_poll }, /* poll */ 871 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 872 { &vop_revoke_desc, spec_revoke }, /* revoke */ 873 { &vop_mmap_desc, spec_mmap }, /* mmap */ 874 { &vop_fsync_desc, spec_fsync }, /* fsync */ 875 { &vop_seek_desc, spec_seek }, /* seek */ 876 { &vop_remove_desc, spec_remove }, /* remove */ 877 { &vop_link_desc, spec_link }, /* link */ 878 { &vop_rename_desc, spec_rename }, /* rename */ 879 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 880 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 881 { &vop_symlink_desc, spec_symlink }, /* symlink */ 882 { &vop_readdir_desc, spec_readdir }, /* readdir */ 883 { &vop_readlink_desc, spec_readlink }, /* readlink */ 884 { &vop_abortop_desc, spec_abortop }, /* abortop */ 885 { &vop_inactive_desc, efs_inactive }, /* inactive */ 886 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 887 { &vop_lock_desc, genfs_lock, }, /* lock */ 888 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 889 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 890 { &vop_bmap_desc, spec_bmap }, /* bmap */ 891 { &vop_print_desc, efs_print }, /* print */ 892 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 893 { &vop_advlock_desc, spec_advlock }, /* advlock */ 894 /* blkatoff */ 895 /* valloc */ 896 /* balloc */ 897 /* vfree */ 898 /* truncate */ 899 /* whiteout */ 900 { &vop_getpages_desc, spec_getpages }, /* getpages */ 901 { &vop_putpages_desc, spec_putpages }, /* putpages */ 902 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 903 { &vop_strategy_desc, spec_strategy }, /* strategy */ 904 { NULL, NULL } 905 }; 906 const struct vnodeopv_desc efs_specop_opv_desc = { 907 &efs_specop_p, 908 efs_specop_entries 909 }; 910 911 int (**efs_fifoop_p)(void *); 912 const struct vnodeopv_entry_desc efs_fifoop_entries[] = { 913 { &vop_default_desc, vn_default_error}, /* error handler */ 914 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 915 { &vop_create_desc, vn_fifo_bypass }, /* create */ 916 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 917 { &vop_open_desc, vn_fifo_bypass }, /* open */ 918 { &vop_close_desc, vn_fifo_bypass }, /* close */ 919 { &vop_access_desc, efs_access }, /* access */ 920 { &vop_getattr_desc, efs_getattr }, /* getattr */ 921 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 922 { &vop_read_desc, vn_fifo_bypass }, /* read */ 923 { &vop_write_desc, vn_fifo_bypass }, /* write */ 924 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 925 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 926 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 927 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 928 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 929 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 930 { &vop_fsync_desc, vn_fifo_bypass }, /* fsync */ 931 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 932 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 933 { &vop_link_desc, vn_fifo_bypass }, /* link */ 934 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 935 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 936 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 937 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 938 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 939 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 940 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 941 { &vop_inactive_desc, efs_inactive }, /* inactive */ 942 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 943 { &vop_lock_desc, genfs_lock, }, /* lock */ 944 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 945 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 946 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 947 { &vop_print_desc, efs_print }, /* print */ 948 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 949 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 950 /* blkatoff */ 951 /* valloc */ 952 /* balloc */ 953 /* vfree */ 954 /* truncate */ 955 /* whiteout */ 956 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 957 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 958 { NULL, NULL } 959 }; 960 const struct vnodeopv_desc efs_fifoop_opv_desc = { 961 &efs_fifoop_p, 962 efs_fifoop_entries 963 }; 964