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