1 /* $NetBSD: efs_vnops.c,v 1.23 2010/11/30 10:43:02 dholland 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.23 2010/11/30 10:43:02 dholland 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 cache_purge(vp); 601 genfs_node_destroy(vp); 602 pool_put(&efs_inode_pool, vp->v_data); 603 vp->v_data = NULL; 604 605 return (0); 606 } 607 608 static int 609 efs_bmap(void *v) 610 { 611 struct vop_bmap_args /* { 612 const struct vnodeop_desc *a_desc; 613 struct vnode *a_vp; 614 daddr_t a_bn; 615 struct vnode **a_vpp; 616 daddr_t *a_bnp; 617 int *a_runp; 618 } */ *ap = v; 619 struct efs_extent ex; 620 struct efs_extent_iterator exi; 621 struct vnode *vp = ap->a_vp; 622 struct efs_inode *eip = EFS_VTOI(vp); 623 bool found; 624 int ret; 625 626 if (ap->a_vpp != NULL) 627 *ap->a_vpp = VFSTOEFS(vp->v_mount)->em_devvp; 628 629 found = false; 630 efs_extent_iterator_init(&exi, eip, ap->a_bn * EFS_BB_SIZE); 631 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 632 if (ap->a_bn >= ex.ex_offset && 633 ap->a_bn < (ex.ex_offset + ex.ex_length)) { 634 found = true; 635 break; 636 } 637 } 638 639 KASSERT(!found || (found && ret == 0)); 640 641 if (!found) { 642 EFS_DPRINTF(("efs_bmap: ap->a_bn not in extents\n")); 643 return ((ret == -1) ? EIO : ret); 644 } 645 646 if (ex.ex_magic != EFS_EXTENT_MAGIC) { 647 EFS_DPRINTF(("efs_bmap: exn.ex_magic != EFS_EXTENT_MAGIC\n")); 648 return (EIO); 649 } 650 651 if (ap->a_bn < ex.ex_offset) { 652 EFS_DPRINTF(("efs_bmap: ap->a_bn < exn.ex_offset\n")); 653 return (EIO); 654 } 655 656 KASSERT(ap->a_bn >= ex.ex_offset); 657 KASSERT(ex.ex_length > ap->a_bn - ex.ex_offset); 658 659 *ap->a_bnp = ex.ex_bn + (ap->a_bn - ex.ex_offset); 660 if (ap->a_runp != NULL) 661 *ap->a_runp = ex.ex_length - (ap->a_bn - ex.ex_offset) - 1; 662 663 return (0); 664 } 665 666 static int 667 efs_strategy(void *v) 668 { 669 struct vop_strategy_args /* { 670 const struct vnodeop_desc *a_desc; 671 struct vnode *a_vp; 672 struct buf *a_bp; 673 } */ *ap = v; 674 struct vnode *vp = ap->a_vp; 675 struct buf *bp = ap->a_bp; 676 int error; 677 678 if (vp == NULL) { 679 bp->b_error = EIO; 680 biodone(bp); 681 return (EIO); 682 } 683 684 if (bp->b_blkno == bp->b_lblkno) { 685 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 686 if (error) { 687 bp->b_error = error; 688 biodone(bp); 689 return (error); 690 } 691 if ((long)bp->b_blkno == -1) 692 clrbuf(bp); 693 } 694 695 if ((long)bp->b_blkno == -1) { 696 biodone(bp); 697 return (0); 698 } 699 700 return (VOP_STRATEGY(VFSTOEFS(vp->v_mount)->em_devvp, bp)); 701 } 702 703 static int 704 efs_print(void *v) 705 { 706 struct vop_print_args /* { 707 const struct vnodeop_desc *a_desc; 708 struct vnode *a_vp; 709 } */ *ap = v; 710 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 711 712 printf( "efs_inode (ino %lu):\n" 713 " ei_mode: %07o\n" 714 " ei_nlink: %d\n" 715 " ei_uid: %d\n" 716 " ei_gid: %d\n" 717 " ei_size: %d\n" 718 " ei_atime: %d\n" 719 " ei_mtime: %d\n" 720 " ei_ctime: %d\n" 721 " ei_gen: %d\n" 722 " ei_numextents: %d\n" 723 " ei_version: %d\n", 724 (unsigned long)eip->ei_number, 725 (unsigned int)eip->ei_mode, 726 eip->ei_nlink, 727 eip->ei_uid, 728 eip->ei_gid, 729 eip->ei_size, 730 (int32_t)eip->ei_atime, 731 (int32_t)eip->ei_mtime, 732 (int32_t)eip->ei_ctime, 733 eip->ei_gen, 734 eip->ei_numextents, 735 eip->ei_version); 736 737 return (0); 738 } 739 740 static int 741 efs_pathconf(void *v) 742 { 743 struct vop_pathconf_args /* { 744 const struct vnodeop_desc *a_desc; 745 struct vnode *a_vp; 746 int a_name; 747 register_t *a_retval; 748 } */ *ap = v; 749 750 /* IRIX 4 values */ 751 switch (ap->a_name) { 752 case _PC_LINK_MAX: 753 *ap->a_retval = 30000; 754 break; 755 case _PC_NAME_MAX: 756 *ap->a_retval = 255; 757 break; 758 case _PC_PATH_MAX: 759 *ap->a_retval = 1024; 760 break; 761 case _PC_NO_TRUNC: 762 *ap->a_retval = 1; 763 break; 764 case _PC_CHOWN_RESTRICTED: 765 *ap->a_retval = 1; 766 break; 767 case _PC_SYNC_IO: 768 *ap->a_retval = 1; 769 break; 770 case _PC_FILESIZEBITS: 771 *ap->a_retval = 32; 772 break; 773 default: 774 return (EINVAL); 775 } 776 777 return (0); 778 } 779 780 static int 781 efs_advlock(void *v) 782 { 783 struct vop_advlock_args /* { 784 const struct vnodeop_desc *a_desc; 785 struct vnode *a_vp; 786 void *a_id; 787 int a_op; 788 struct flock *a_fl; 789 int a_flags; 790 } */ *ap = v; 791 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 792 793 return (lf_advlock(ap, &eip->ei_lockf, eip->ei_size)); 794 } 795 796 /* Global vfs data structures for efs */ 797 int (**efs_vnodeop_p)(void *); 798 const struct vnodeopv_entry_desc efs_vnodeop_entries[] = { 799 { &vop_default_desc, vn_default_error}, /* error handler */ 800 { &vop_lookup_desc, efs_lookup }, /* lookup */ 801 { &vop_create_desc, genfs_eopnotsupp}, /* create */ 802 { &vop_mknod_desc, genfs_eopnotsupp}, /* mknod */ 803 { &vop_open_desc, genfs_nullop }, /* open */ 804 { &vop_close_desc, genfs_nullop }, /* close */ 805 { &vop_access_desc, efs_access }, /* access */ 806 { &vop_getattr_desc, efs_getattr }, /* getattr */ 807 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 808 { &vop_read_desc, efs_read }, /* read */ 809 { &vop_write_desc, genfs_eopnotsupp}, /* write */ 810 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ 811 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 812 { &vop_poll_desc, genfs_poll }, /* poll */ 813 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 814 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 815 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 816 { &vop_fsync_desc, genfs_eopnotsupp}, /* fsync */ 817 { &vop_seek_desc, genfs_seek }, /* seek */ 818 { &vop_remove_desc, genfs_eopnotsupp}, /* remove */ 819 { &vop_link_desc, genfs_eopnotsupp}, /* link */ 820 { &vop_rename_desc, genfs_eopnotsupp}, /* rename */ 821 { &vop_mkdir_desc, genfs_eopnotsupp}, /* mkdir */ 822 { &vop_rmdir_desc, genfs_eopnotsupp}, /* rmdir */ 823 { &vop_symlink_desc, genfs_eopnotsupp}, /* symlink */ 824 { &vop_readdir_desc, efs_readdir }, /* readdir */ 825 { &vop_readlink_desc, efs_readlink }, /* readlink */ 826 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 827 { &vop_inactive_desc, efs_inactive }, /* inactive */ 828 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 829 { &vop_lock_desc, genfs_lock, }, /* lock */ 830 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 831 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 832 { &vop_bmap_desc, efs_bmap }, /* bmap */ 833 { &vop_print_desc, efs_print }, /* print */ 834 { &vop_pathconf_desc, efs_pathconf }, /* pathconf */ 835 { &vop_advlock_desc, efs_advlock }, /* advlock */ 836 /* blkatoff */ 837 /* valloc */ 838 /* balloc */ 839 /* vfree */ 840 /* truncate */ 841 /* whiteout */ 842 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 843 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 844 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 845 { &vop_strategy_desc, efs_strategy }, /* strategy */ 846 { NULL, NULL } 847 }; 848 const struct vnodeopv_desc efs_vnodeop_opv_desc = { 849 &efs_vnodeop_p, 850 efs_vnodeop_entries 851 }; 852 853 int (**efs_specop_p)(void *); 854 const struct vnodeopv_entry_desc efs_specop_entries[] = { 855 { &vop_default_desc, vn_default_error}, /* error handler */ 856 { &vop_lookup_desc, spec_lookup }, /* lookup */ 857 { &vop_create_desc, spec_create }, /* create */ 858 { &vop_mknod_desc, spec_mknod }, /* mknod */ 859 { &vop_open_desc, spec_open }, /* open */ 860 { &vop_close_desc, spec_close }, /* close */ 861 { &vop_access_desc, efs_access }, /* access */ 862 { &vop_getattr_desc, efs_getattr }, /* getattr */ 863 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 864 { &vop_read_desc, spec_read }, /* read */ 865 { &vop_write_desc, spec_write }, /* write */ 866 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 867 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 868 { &vop_poll_desc, spec_poll }, /* poll */ 869 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 870 { &vop_revoke_desc, spec_revoke }, /* revoke */ 871 { &vop_mmap_desc, spec_mmap }, /* mmap */ 872 { &vop_fsync_desc, spec_fsync }, /* fsync */ 873 { &vop_seek_desc, spec_seek }, /* seek */ 874 { &vop_remove_desc, spec_remove }, /* remove */ 875 { &vop_link_desc, spec_link }, /* link */ 876 { &vop_rename_desc, spec_rename }, /* rename */ 877 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 878 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 879 { &vop_symlink_desc, spec_symlink }, /* symlink */ 880 { &vop_readdir_desc, spec_readdir }, /* readdir */ 881 { &vop_readlink_desc, spec_readlink }, /* readlink */ 882 { &vop_abortop_desc, spec_abortop }, /* abortop */ 883 { &vop_inactive_desc, efs_inactive }, /* inactive */ 884 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 885 { &vop_lock_desc, genfs_lock, }, /* lock */ 886 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 887 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 888 { &vop_bmap_desc, spec_bmap }, /* bmap */ 889 { &vop_print_desc, efs_print }, /* print */ 890 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 891 { &vop_advlock_desc, spec_advlock }, /* advlock */ 892 /* blkatoff */ 893 /* valloc */ 894 /* balloc */ 895 /* vfree */ 896 /* truncate */ 897 /* whiteout */ 898 { &vop_getpages_desc, spec_getpages }, /* getpages */ 899 { &vop_putpages_desc, spec_putpages }, /* putpages */ 900 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 901 { &vop_strategy_desc, spec_strategy }, /* strategy */ 902 { NULL, NULL } 903 }; 904 const struct vnodeopv_desc efs_specop_opv_desc = { 905 &efs_specop_p, 906 efs_specop_entries 907 }; 908 909 int (**efs_fifoop_p)(void *); 910 const struct vnodeopv_entry_desc efs_fifoop_entries[] = { 911 { &vop_default_desc, vn_default_error}, /* error handler */ 912 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 913 { &vop_create_desc, vn_fifo_bypass }, /* create */ 914 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 915 { &vop_open_desc, vn_fifo_bypass }, /* open */ 916 { &vop_close_desc, vn_fifo_bypass }, /* close */ 917 { &vop_access_desc, efs_access }, /* access */ 918 { &vop_getattr_desc, efs_getattr }, /* getattr */ 919 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 920 { &vop_read_desc, vn_fifo_bypass }, /* read */ 921 { &vop_write_desc, vn_fifo_bypass }, /* write */ 922 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 923 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 924 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 925 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 926 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 927 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 928 { &vop_fsync_desc, vn_fifo_bypass }, /* fsync */ 929 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 930 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 931 { &vop_link_desc, vn_fifo_bypass }, /* link */ 932 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 933 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 934 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 935 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 936 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 937 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 938 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 939 { &vop_inactive_desc, efs_inactive }, /* inactive */ 940 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 941 { &vop_lock_desc, genfs_lock, }, /* lock */ 942 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 943 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 944 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 945 { &vop_print_desc, efs_print }, /* print */ 946 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 947 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 948 /* blkatoff */ 949 /* valloc */ 950 /* balloc */ 951 /* vfree */ 952 /* truncate */ 953 /* whiteout */ 954 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 955 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 956 { NULL, NULL } 957 }; 958 const struct vnodeopv_desc efs_fifoop_opv_desc = { 959 &efs_fifoop_p, 960 efs_fifoop_entries 961 }; 962