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