1 /* $NetBSD: efs_vnops.c,v 1.30 2013/03/18 19:35:36 plunky 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.30 2013/03/18 19:35:36 plunky 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 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 return 0; 129 } 130 131 static int 132 efs_check_possible(struct vnode *vp, struct efs_inode *eip, mode_t mode) 133 { 134 135 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 136 return (EROFS); 137 138 return 0; 139 } 140 141 /* 142 * Determine the accessiblity of a file based on the permissions allowed by the 143 * specified credentials. 144 * 145 * Returns 0 on success. 146 */ 147 static int 148 efs_check_permitted(struct vnode *vp, struct efs_inode *eip, mode_t mode, 149 kauth_cred_t cred) 150 { 151 152 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, 153 vp->v_type, eip->ei_mode), vp, NULL, genfs_can_access(vp->v_type, 154 eip->ei_mode, eip->ei_uid, eip->ei_gid, mode, cred)); 155 } 156 157 static int 158 efs_access(void *v) 159 { 160 struct vop_access_args /* { 161 const struct vnodeop_desc *a_desc; 162 struct vnode *a_vp; 163 int a_mode; 164 struct ucred *a_cred; 165 } */ *ap = v; 166 struct vnode *vp = ap->a_vp; 167 struct efs_inode *eip = EFS_VTOI(vp); 168 int error; 169 170 error = efs_check_possible(vp, eip, ap->a_mode); 171 if (error) 172 return error; 173 174 error = efs_check_permitted(vp, eip, ap->a_mode, ap->a_cred); 175 176 return error; 177 } 178 179 /* 180 * Get specific vnode attributes on a file. See vattr(9). 181 * 182 * Returns 0 on success. 183 */ 184 static int 185 efs_getattr(void *v) 186 { 187 struct vop_getattr_args /* { 188 const struct vnodeop_desc *a_desc; 189 struct vnode *a_vp; 190 struct vattr *a_vap; 191 struct ucred *a_cred; 192 } */ *ap = v; 193 194 struct vattr *vap = ap->a_vap; 195 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 196 197 vattr_null(ap->a_vap); 198 vap->va_type = ap->a_vp->v_type; 199 vap->va_mode = eip->ei_mode; 200 vap->va_nlink = eip->ei_nlink; 201 vap->va_uid = eip->ei_uid; 202 vap->va_gid = eip->ei_gid; 203 vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 204 vap->va_fileid = eip->ei_number; 205 vap->va_size = eip->ei_size; 206 207 if (ap->a_vp->v_type == VBLK) 208 vap->va_blocksize = BLKDEV_IOSIZE; 209 else if (ap->a_vp->v_type == VCHR) 210 vap->va_blocksize = MAXBSIZE; 211 else 212 vap->va_blocksize = EFS_BB_SIZE; 213 214 vap->va_atime.tv_sec = eip->ei_atime; 215 vap->va_mtime.tv_sec = eip->ei_mtime; 216 vap->va_ctime.tv_sec = eip->ei_ctime; 217 /* vap->va_birthtime = */ 218 vap->va_gen = eip->ei_gen; 219 vap->va_flags = ap->a_vp->v_vflag | 220 ap->a_vp->v_iflag | ap->a_vp->v_uflag; 221 222 if (ap->a_vp->v_type == VBLK || ap->a_vp->v_type == VCHR) { 223 uint32_t dmaj, dmin; 224 225 if (be16toh(eip->ei_di.di_odev) != EFS_DINODE_ODEV_INVALID) { 226 dmaj = EFS_DINODE_ODEV_MAJ(be16toh(eip->ei_di.di_odev)); 227 dmin = EFS_DINODE_ODEV_MIN(be16toh(eip->ei_di.di_odev)); 228 } else { 229 dmaj = EFS_DINODE_NDEV_MAJ(be32toh(eip->ei_di.di_ndev)); 230 dmin = EFS_DINODE_NDEV_MIN(be32toh(eip->ei_di.di_ndev)); 231 } 232 233 vap->va_rdev = makedev(dmaj, dmin); 234 } 235 236 vap->va_bytes = eip->ei_size; 237 /* vap->va_filerev = */ 238 /* vap->va_vaflags = */ 239 240 return (0); 241 } 242 243 /* 244 * Read a file. 245 * 246 * Returns 0 on success. 247 */ 248 static int 249 efs_read(void *v) 250 { 251 struct vop_read_args /* { 252 const struct vnodeop_desc *a_desc; 253 struct vnode *a_vp; 254 struct uio *a_uio; 255 int a_ioflag; 256 struct ucred *a_cred; 257 } */ *ap = v; 258 struct efs_extent ex; 259 struct efs_extent_iterator exi; 260 struct uio *uio = ap->a_uio; 261 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 262 off_t start; 263 vsize_t len; 264 int err, ret; 265 const int advice = IO_ADV_DECODE(ap->a_ioflag); 266 267 if (ap->a_vp->v_type == VDIR) 268 return (EISDIR); 269 270 if (ap->a_vp->v_type != VREG) 271 return (EINVAL); 272 273 efs_extent_iterator_init(&exi, eip, uio->uio_offset); 274 ret = efs_extent_iterator_next(&exi, &ex); 275 while (ret == 0) { 276 if (uio->uio_offset < 0 || uio->uio_offset >= eip->ei_size || 277 uio->uio_resid == 0) 278 break; 279 280 start = ex.ex_offset * EFS_BB_SIZE; 281 len = ex.ex_length * EFS_BB_SIZE; 282 283 if (!(uio->uio_offset >= start && 284 uio->uio_offset < (start + len))) { 285 ret = efs_extent_iterator_next(&exi, &ex); 286 continue; 287 } 288 289 start = uio->uio_offset - start; 290 291 len = MIN(len - start, uio->uio_resid); 292 len = MIN(len, eip->ei_size - uio->uio_offset); 293 294 err = ubc_uiomove(&ap->a_vp->v_uobj, uio, len, advice, 295 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(ap->a_vp)); 296 if (err) { 297 EFS_DPRINTF(("efs_read: uiomove error %d\n", 298 err)); 299 return (err); 300 } 301 } 302 303 return ((ret == -1) ? 0 : ret); 304 } 305 306 static int 307 efs_readdir(void *v) 308 { 309 struct vop_readdir_args /* { 310 const struct vnodeop_desc *a_desc; 311 struct vnode *a_vp; 312 struct uio *a_uio; 313 struct ucred *a_cred; 314 int *a_eofflag; 315 off_t **a_cookies; 316 int *a_ncookies; 317 } */ *ap = v; 318 struct dirent *dp; 319 struct efs_dinode edi; 320 struct efs_extent ex; 321 struct efs_extent_iterator exi; 322 struct buf *bp; 323 struct efs_dirent *de; 324 struct efs_dirblk *db; 325 struct uio *uio = ap->a_uio; 326 struct efs_inode *ei = EFS_VTOI(ap->a_vp); 327 off_t *cookies = NULL; 328 off_t offset; 329 int i, j, err, ret, s, slot, ncookies, maxcookies = 0; 330 331 if (ap->a_vp->v_type != VDIR) 332 return (ENOTDIR); 333 334 if (ap->a_eofflag != NULL) 335 *ap->a_eofflag = false; 336 337 if (ap->a_ncookies != NULL) { 338 ncookies = 0; 339 maxcookies = 340 uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); 341 cookies = malloc(maxcookies * sizeof(off_t), M_TEMP, M_WAITOK); 342 } 343 344 dp = malloc(sizeof(struct dirent), M_EFSTMP, M_WAITOK | M_ZERO); 345 346 offset = 0; 347 efs_extent_iterator_init(&exi, ei, 0); 348 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 349 for (i = 0; i < ex.ex_length; i++) { 350 err = efs_bread(VFSTOEFS(ap->a_vp->v_mount), 351 ex.ex_bn + i, NULL, &bp); 352 if (err) { 353 goto exit_err; 354 } 355 356 db = (struct efs_dirblk *)bp->b_data; 357 358 if (be16toh(db->db_magic) != EFS_DIRBLK_MAGIC) { 359 printf("efs_readdir: bad dirblk\n"); 360 brelse(bp, 0); 361 continue; 362 } 363 364 for (j = 0; j < db->db_slots; j++) { 365 slot = EFS_DIRENT_OFF_EXPND(db->db_space[j]); 366 if (slot == EFS_DIRBLK_SLOT_FREE) 367 continue; 368 369 if (!EFS_DIRENT_OFF_VALID(slot)) { 370 printf("efs_readdir: bad dirent\n"); 371 continue; 372 } 373 374 de = EFS_DIRBLK_TO_DIRENT(db, slot); 375 s = _DIRENT_RECLEN(dp, de->de_namelen); 376 377 if (offset < uio->uio_offset) { 378 offset += s; 379 continue; 380 } 381 382 /* XXX - shouldn't happen, right? */ 383 if (offset > uio->uio_offset || 384 s > uio->uio_resid) { 385 brelse(bp, 0); 386 goto exit_ok; 387 } 388 389 /* de_namelen is uint8_t, d.d_name is 512b */ 390 KASSERT(sizeof(dp->d_name)-de->de_namelen > 0); 391 dp->d_fileno = be32toh(de->de_inumber); 392 dp->d_reclen = s; 393 dp->d_namlen = de->de_namelen; 394 memcpy(dp->d_name, de->de_name, 395 de->de_namelen); 396 dp->d_name[de->de_namelen] = '\0'; 397 398 /* look up inode to get type */ 399 err = efs_read_inode( 400 VFSTOEFS(ap->a_vp->v_mount), 401 dp->d_fileno, NULL, &edi); 402 if (err) { 403 brelse(bp, 0); 404 goto exit_err; 405 } 406 407 switch (be16toh(edi.di_mode) & EFS_IFMT) { 408 case EFS_IFIFO: 409 dp->d_type = DT_FIFO; 410 break; 411 case EFS_IFCHR: 412 dp->d_type = DT_CHR; 413 break; 414 case EFS_IFDIR: 415 dp->d_type = DT_DIR; 416 break; 417 case EFS_IFBLK: 418 dp->d_type = DT_BLK; 419 break; 420 case EFS_IFREG: 421 dp->d_type = DT_REG; 422 break; 423 case EFS_IFLNK: 424 dp->d_type = DT_LNK; 425 break; 426 case EFS_IFSOCK: 427 dp->d_type = DT_SOCK; 428 break; 429 default: 430 dp->d_type = DT_UNKNOWN; 431 break; 432 } 433 434 err = uiomove(dp, s, uio); 435 if (err) { 436 brelse(bp, 0); 437 goto exit_err; 438 } 439 440 offset += s; 441 442 if (cookies != NULL && maxcookies != 0) { 443 cookies[ncookies++] = offset; 444 if (ncookies == maxcookies) { 445 brelse(bp, 0); 446 goto exit_ok; 447 } 448 } 449 } 450 451 brelse(bp, 0); 452 } 453 } 454 455 if (ret != -1) { 456 err = ret; 457 goto exit_err; 458 } 459 460 if (ap->a_eofflag != NULL) 461 *ap->a_eofflag = true; 462 463 exit_ok: 464 if (cookies != NULL) { 465 *ap->a_cookies = cookies; 466 *ap->a_ncookies = ncookies; 467 } 468 469 uio->uio_offset = offset; 470 471 free(dp, M_EFSTMP); 472 473 return (0); 474 475 exit_err: 476 if (cookies != NULL) 477 free(cookies, M_TEMP); 478 479 free(dp, M_EFSTMP); 480 481 return (err); 482 } 483 484 static int 485 efs_readlink(void *v) 486 { 487 struct vop_readlink_args /* { 488 const struct vnodeop_desc *a_desc; 489 struct vnode *a_vp; 490 struct uio *a_uio; 491 struct ucred *a_cred; 492 } */ *ap = v; 493 struct uio *uio = ap->a_uio; 494 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 495 char *buf; 496 size_t len; 497 int err, i; 498 499 if ((eip->ei_mode & EFS_IFMT) != EFS_IFLNK) 500 return (EINVAL); 501 502 if (uio->uio_resid < 1) 503 return (EINVAL); 504 505 buf = malloc(eip->ei_size + 1, M_EFSTMP, M_ZERO | M_WAITOK); 506 507 /* symlinks are either inlined in the inode, or in extents */ 508 if (eip->ei_numextents == 0) { 509 if (eip->ei_size > sizeof(eip->ei_di.di_symlink)) { 510 EFS_DPRINTF(("efs_readlink: too big for inline\n")); 511 free(buf, M_EFSTMP); 512 return (EBADF); 513 } 514 515 memcpy(buf, eip->ei_di.di_symlink, eip->ei_size); 516 len = MIN(uio->uio_resid, eip->ei_size + 1); 517 } else { 518 struct efs_extent_iterator exi; 519 struct efs_extent ex; 520 struct buf *bp; 521 int resid, off, ret; 522 523 off = 0; 524 resid = eip->ei_size; 525 526 efs_extent_iterator_init(&exi, eip, 0); 527 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 528 for (i = 0; i < ex.ex_length; i++) { 529 err = efs_bread(VFSTOEFS(ap->a_vp->v_mount), 530 ex.ex_bn + i, NULL, &bp); 531 if (err) { 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