1 /* $NetBSD: efs_vnops.c,v 1.20 2009/07/03 22:25:51 pooka 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.20 2009/07/03 22:25:51 pooka 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, 0); /* 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 cnp->cn_flags |= SAVENAME; 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 if (cnp->cn_flags & MAKEENTRY) 126 cache_enter(ap->a_dvp, *ap->a_vpp, cnp); 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 genfs_can_access(vp->v_type, eip->ei_mode, eip->ei_uid, 153 eip->ei_gid, mode, cred); 154 } 155 156 static int 157 efs_access(void *v) 158 { 159 struct vop_access_args /* { 160 const struct vnodeop_desc *a_desc; 161 struct vnode *a_vp; 162 int a_mode; 163 struct ucred *a_cred; 164 } */ *ap = v; 165 struct vnode *vp = ap->a_vp; 166 struct efs_inode *eip = EFS_VTOI(vp); 167 int error; 168 169 error = efs_check_possible(vp, eip, ap->a_mode); 170 if (error) 171 return error; 172 173 error = efs_check_permitted(vp, eip, ap->a_mode, ap->a_cred); 174 175 return error; 176 } 177 178 /* 179 * Get specific vnode attributes on a file. See vattr(9). 180 * 181 * Returns 0 on success. 182 */ 183 static int 184 efs_getattr(void *v) 185 { 186 struct vop_getattr_args /* { 187 const struct vnodeop_desc *a_desc; 188 struct vnode *a_vp; 189 struct vattr *a_vap; 190 struct ucred *a_cred; 191 } */ *ap = v; 192 193 struct vattr *vap = ap->a_vap; 194 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 195 196 vattr_null(ap->a_vap); 197 vap->va_type = ap->a_vp->v_type; 198 vap->va_mode = eip->ei_mode; 199 vap->va_nlink = eip->ei_nlink; 200 vap->va_uid = eip->ei_uid; 201 vap->va_gid = eip->ei_gid; 202 vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 203 vap->va_fileid = eip->ei_number; 204 vap->va_size = eip->ei_size; 205 206 if (ap->a_vp->v_type == VBLK) 207 vap->va_blocksize = BLKDEV_IOSIZE; 208 else if (ap->a_vp->v_type == VCHR) 209 vap->va_blocksize = MAXBSIZE; 210 else 211 vap->va_blocksize = EFS_BB_SIZE; 212 213 vap->va_atime.tv_sec = eip->ei_atime; 214 vap->va_mtime.tv_sec = eip->ei_mtime; 215 vap->va_ctime.tv_sec = eip->ei_ctime; 216 /* vap->va_birthtime = */ 217 vap->va_gen = eip->ei_gen; 218 vap->va_flags = ap->a_vp->v_vflag | 219 ap->a_vp->v_iflag | ap->a_vp->v_uflag; 220 221 if (ap->a_vp->v_type == VBLK || ap->a_vp->v_type == VCHR) { 222 uint32_t dmaj, dmin; 223 224 if (be16toh(eip->ei_di.di_odev) != EFS_DINODE_ODEV_INVALID) { 225 dmaj = EFS_DINODE_ODEV_MAJ(be16toh(eip->ei_di.di_odev)); 226 dmin = EFS_DINODE_ODEV_MIN(be16toh(eip->ei_di.di_odev)); 227 } else { 228 dmaj = EFS_DINODE_NDEV_MAJ(be32toh(eip->ei_di.di_ndev)); 229 dmin = EFS_DINODE_NDEV_MIN(be32toh(eip->ei_di.di_ndev)); 230 } 231 232 vap->va_rdev = makedev(dmaj, dmin); 233 } 234 235 vap->va_bytes = eip->ei_size; 236 /* vap->va_filerev = */ 237 /* vap->va_vaflags = */ 238 239 return (0); 240 } 241 242 /* 243 * Read a file. 244 * 245 * Returns 0 on success. 246 */ 247 static int 248 efs_read(void *v) 249 { 250 struct vop_read_args /* { 251 const struct vnodeop_desc *a_desc; 252 struct vnode *a_vp; 253 struct uio *a_uio; 254 int a_ioflag; 255 struct ucred *a_cred; 256 } */ *ap = v; 257 struct efs_extent ex; 258 struct efs_extent_iterator exi; 259 struct uio *uio = ap->a_uio; 260 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 261 off_t start; 262 vsize_t len; 263 int err, ret; 264 const int advice = IO_ADV_DECODE(ap->a_ioflag); 265 266 if (ap->a_vp->v_type == VDIR) 267 return (EISDIR); 268 269 if (ap->a_vp->v_type != VREG) 270 return (EINVAL); 271 272 efs_extent_iterator_init(&exi, eip, uio->uio_offset); 273 ret = efs_extent_iterator_next(&exi, &ex); 274 while (ret == 0) { 275 if (uio->uio_offset < 0 || uio->uio_offset >= eip->ei_size || 276 uio->uio_resid == 0) 277 break; 278 279 start = ex.ex_offset * EFS_BB_SIZE; 280 len = ex.ex_length * EFS_BB_SIZE; 281 282 if (!(uio->uio_offset >= start && 283 uio->uio_offset < (start + len))) { 284 ret = efs_extent_iterator_next(&exi, &ex); 285 continue; 286 } 287 288 start = uio->uio_offset - start; 289 290 len = MIN(len - start, uio->uio_resid); 291 len = MIN(len, eip->ei_size - uio->uio_offset); 292 293 err = ubc_uiomove(&ap->a_vp->v_uobj, uio, len, advice, 294 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(ap->a_vp)); 295 if (err) { 296 EFS_DPRINTF(("efs_read: uiomove error %d\n", 297 err)); 298 return (err); 299 } 300 } 301 302 return ((ret == -1) ? 0 : ret); 303 } 304 305 static int 306 efs_readdir(void *v) 307 { 308 struct vop_readdir_args /* { 309 const struct vnodeop_desc *a_desc; 310 struct vnode *a_vp; 311 struct uio *a_uio; 312 struct ucred *a_cred; 313 int *a_eofflag; 314 off_t **a_cookies; 315 int *a_ncookies; 316 } */ *ap = v; 317 struct dirent *dp; 318 struct efs_dinode edi; 319 struct efs_extent ex; 320 struct efs_extent_iterator exi; 321 struct buf *bp; 322 struct efs_dirent *de; 323 struct efs_dirblk *db; 324 struct uio *uio = ap->a_uio; 325 struct efs_inode *ei = EFS_VTOI(ap->a_vp); 326 off_t *cookies = NULL; 327 off_t offset; 328 int i, j, err, ret, s, slot, ncookies, maxcookies = 0; 329 330 if (ap->a_vp->v_type != VDIR) 331 return (ENOTDIR); 332 333 if (ap->a_eofflag != NULL) 334 *ap->a_eofflag = false; 335 336 if (ap->a_ncookies != NULL) { 337 ncookies = 0; 338 maxcookies = 339 uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); 340 cookies = malloc(maxcookies * sizeof(off_t), M_TEMP, M_WAITOK); 341 } 342 343 dp = malloc(sizeof(struct dirent), M_EFSTMP, M_WAITOK | M_ZERO); 344 345 offset = 0; 346 efs_extent_iterator_init(&exi, ei, 0); 347 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 348 for (i = 0; i < ex.ex_length; i++) { 349 err = efs_bread(VFSTOEFS(ap->a_vp->v_mount), 350 ex.ex_bn + i, NULL, &bp); 351 if (err) { 352 brelse(bp, 0); 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 brelse(bp, 0); 533 free(buf, M_EFSTMP); 534 return (err); 535 } 536 537 len = MIN(resid, bp->b_bcount); 538 memcpy(buf + off, bp->b_data, len); 539 brelse(bp, 0); 540 541 off += len; 542 resid -= len; 543 544 if (resid == 0) 545 break; 546 } 547 548 if (resid == 0) 549 break; 550 } 551 552 if (ret != 0 && ret != -1) { 553 free(buf, M_EFSTMP); 554 return (ret); 555 } 556 557 len = off + 1; 558 } 559 560 KASSERT(len >= 1 && len <= (eip->ei_size + 1)); 561 buf[len - 1] = '\0'; 562 err = uiomove(buf, len, uio); 563 free(buf, M_EFSTMP); 564 565 return (err); 566 } 567 568 /* 569 * Release an inactive vnode. The vnode _must_ be unlocked on return. 570 * It is either nolonger being used by the kernel, or an unmount is being 571 * forced. 572 * 573 * Returns 0 on success. 574 */ 575 static int 576 efs_inactive(void *v) 577 { 578 struct vop_inactive_args /* { 579 const struct vnodeop_desc *a_desc; 580 struct vnode *a_vp; 581 bool *a_recycle 582 } */ *ap = v; 583 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 584 585 *ap->a_recycle = (eip->ei_mode == 0); 586 VOP_UNLOCK(ap->a_vp, 0); 587 588 return (0); 589 } 590 591 static int 592 efs_reclaim(void *v) 593 { 594 struct vop_reclaim_args /* { 595 const struct vnodeop_desc *a_desc; 596 struct vnode *a_vp; 597 } */ *ap = v; 598 struct vnode *vp = ap->a_vp; 599 600 efs_ihashrem(EFS_VTOI(vp)); 601 cache_purge(vp); 602 genfs_node_destroy(vp); 603 pool_put(&efs_inode_pool, vp->v_data); 604 vp->v_data = NULL; 605 606 return (0); 607 } 608 609 static int 610 efs_bmap(void *v) 611 { 612 struct vop_bmap_args /* { 613 const struct vnodeop_desc *a_desc; 614 struct vnode *a_vp; 615 daddr_t a_bn; 616 struct vnode **a_vpp; 617 daddr_t *a_bnp; 618 int *a_runp; 619 } */ *ap = v; 620 struct efs_extent ex; 621 struct efs_extent_iterator exi; 622 struct vnode *vp = ap->a_vp; 623 struct efs_inode *eip = EFS_VTOI(vp); 624 bool found; 625 int ret; 626 627 if (ap->a_vpp != NULL) 628 *ap->a_vpp = VFSTOEFS(vp->v_mount)->em_devvp; 629 630 found = false; 631 efs_extent_iterator_init(&exi, eip, ap->a_bn * EFS_BB_SIZE); 632 while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) { 633 if (ap->a_bn >= ex.ex_offset && 634 ap->a_bn < (ex.ex_offset + ex.ex_length)) { 635 found = true; 636 break; 637 } 638 } 639 640 KASSERT(!found || (found && ret == 0)); 641 642 if (!found) { 643 EFS_DPRINTF(("efs_bmap: ap->a_bn not in extents\n")); 644 return ((ret == -1) ? EIO : ret); 645 } 646 647 if (ex.ex_magic != EFS_EXTENT_MAGIC) { 648 EFS_DPRINTF(("efs_bmap: exn.ex_magic != EFS_EXTENT_MAGIC\n")); 649 return (EIO); 650 } 651 652 if (ap->a_bn < ex.ex_offset) { 653 EFS_DPRINTF(("efs_bmap: ap->a_bn < exn.ex_offset\n")); 654 return (EIO); 655 } 656 657 KASSERT(ap->a_bn >= ex.ex_offset); 658 KASSERT(ex.ex_length > ap->a_bn - ex.ex_offset); 659 660 *ap->a_bnp = ex.ex_bn + (ap->a_bn - ex.ex_offset); 661 if (ap->a_runp != NULL) 662 *ap->a_runp = ex.ex_length - (ap->a_bn - ex.ex_offset) - 1; 663 664 return (0); 665 } 666 667 static int 668 efs_strategy(void *v) 669 { 670 struct vop_strategy_args /* { 671 const struct vnodeop_desc *a_desc; 672 struct vnode *a_vp; 673 struct buf *a_bp; 674 } */ *ap = v; 675 struct vnode *vp = ap->a_vp; 676 struct buf *bp = ap->a_bp; 677 int error; 678 679 if (vp == NULL) { 680 bp->b_error = EIO; 681 biodone(bp); 682 return (EIO); 683 } 684 685 if (bp->b_blkno == bp->b_lblkno) { 686 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 687 if (error) { 688 bp->b_error = error; 689 biodone(bp); 690 return (error); 691 } 692 if ((long)bp->b_blkno == -1) 693 clrbuf(bp); 694 } 695 696 if ((long)bp->b_blkno == -1) { 697 biodone(bp); 698 return (0); 699 } 700 701 return (VOP_STRATEGY(VFSTOEFS(vp->v_mount)->em_devvp, bp)); 702 } 703 704 static int 705 efs_print(void *v) 706 { 707 struct vop_print_args /* { 708 const struct vnodeop_desc *a_desc; 709 struct vnode *a_vp; 710 } */ *ap = v; 711 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 712 713 printf( "efs_inode (ino %lu):\n" 714 " ei_mode: %07o\n" 715 " ei_nlink: %d\n" 716 " ei_uid: %d\n" 717 " ei_gid: %d\n" 718 " ei_size: %d\n" 719 " ei_atime: %d\n" 720 " ei_mtime: %d\n" 721 " ei_ctime: %d\n" 722 " ei_gen: %d\n" 723 " ei_numextents: %d\n" 724 " ei_version: %d\n", 725 (unsigned long)eip->ei_number, 726 (unsigned int)eip->ei_mode, 727 eip->ei_nlink, 728 eip->ei_uid, 729 eip->ei_gid, 730 eip->ei_size, 731 (int32_t)eip->ei_atime, 732 (int32_t)eip->ei_mtime, 733 (int32_t)eip->ei_ctime, 734 eip->ei_gen, 735 eip->ei_numextents, 736 eip->ei_version); 737 738 return (0); 739 } 740 741 static int 742 efs_pathconf(void *v) 743 { 744 struct vop_pathconf_args /* { 745 const struct vnodeop_desc *a_desc; 746 struct vnode *a_vp; 747 int a_name; 748 register_t *a_retval; 749 } */ *ap = v; 750 751 /* IRIX 4 values */ 752 switch (ap->a_name) { 753 case _PC_LINK_MAX: 754 *ap->a_retval = 30000; 755 break; 756 case _PC_NAME_MAX: 757 *ap->a_retval = 255; 758 break; 759 case _PC_PATH_MAX: 760 *ap->a_retval = 1024; 761 break; 762 case _PC_NO_TRUNC: 763 *ap->a_retval = 1; 764 break; 765 case _PC_CHOWN_RESTRICTED: 766 *ap->a_retval = 1; 767 break; 768 case _PC_SYNC_IO: 769 *ap->a_retval = 1; 770 break; 771 case _PC_FILESIZEBITS: 772 *ap->a_retval = 32; 773 break; 774 default: 775 return (EINVAL); 776 } 777 778 return (0); 779 } 780 781 static int 782 efs_advlock(void *v) 783 { 784 struct vop_advlock_args /* { 785 const struct vnodeop_desc *a_desc; 786 struct vnode *a_vp; 787 void *a_id; 788 int a_op; 789 struct flock *a_fl; 790 int a_flags; 791 } */ *ap = v; 792 struct efs_inode *eip = EFS_VTOI(ap->a_vp); 793 794 return (lf_advlock(ap, &eip->ei_lockf, eip->ei_size)); 795 } 796 797 /* Global vfs data structures for efs */ 798 int (**efs_vnodeop_p)(void *); 799 const struct vnodeopv_entry_desc efs_vnodeop_entries[] = { 800 { &vop_default_desc, vn_default_error}, /* error handler */ 801 { &vop_lookup_desc, efs_lookup }, /* lookup */ 802 { &vop_create_desc, genfs_eopnotsupp}, /* create */ 803 { &vop_mknod_desc, genfs_eopnotsupp}, /* mknod */ 804 { &vop_open_desc, genfs_nullop }, /* open */ 805 { &vop_close_desc, genfs_nullop }, /* close */ 806 { &vop_access_desc, efs_access }, /* access */ 807 { &vop_getattr_desc, efs_getattr }, /* getattr */ 808 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 809 { &vop_read_desc, efs_read }, /* read */ 810 { &vop_write_desc, genfs_eopnotsupp}, /* write */ 811 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ 812 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 813 { &vop_poll_desc, genfs_poll }, /* poll */ 814 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 815 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 816 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 817 { &vop_fsync_desc, genfs_eopnotsupp}, /* fsync */ 818 { &vop_seek_desc, genfs_seek }, /* seek */ 819 { &vop_remove_desc, genfs_eopnotsupp}, /* remove */ 820 { &vop_link_desc, genfs_eopnotsupp}, /* link */ 821 { &vop_rename_desc, genfs_eopnotsupp}, /* rename */ 822 { &vop_mkdir_desc, genfs_eopnotsupp}, /* mkdir */ 823 { &vop_rmdir_desc, genfs_eopnotsupp}, /* rmdir */ 824 { &vop_symlink_desc, genfs_eopnotsupp}, /* symlink */ 825 { &vop_readdir_desc, efs_readdir }, /* readdir */ 826 { &vop_readlink_desc, efs_readlink }, /* readlink */ 827 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 828 { &vop_inactive_desc, efs_inactive }, /* inactive */ 829 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 830 { &vop_lock_desc, genfs_lock, }, /* lock */ 831 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 832 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 833 { &vop_bmap_desc, efs_bmap }, /* bmap */ 834 { &vop_print_desc, efs_print }, /* print */ 835 { &vop_pathconf_desc, efs_pathconf }, /* pathconf */ 836 { &vop_advlock_desc, efs_advlock }, /* advlock */ 837 /* blkatoff */ 838 /* valloc */ 839 /* balloc */ 840 /* vfree */ 841 /* truncate */ 842 /* whiteout */ 843 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 844 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 845 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 846 { &vop_strategy_desc, efs_strategy }, /* strategy */ 847 { NULL, NULL } 848 }; 849 const struct vnodeopv_desc efs_vnodeop_opv_desc = { 850 &efs_vnodeop_p, 851 efs_vnodeop_entries 852 }; 853 854 int (**efs_specop_p)(void *); 855 const struct vnodeopv_entry_desc efs_specop_entries[] = { 856 { &vop_default_desc, vn_default_error}, /* error handler */ 857 { &vop_lookup_desc, spec_lookup }, /* lookup */ 858 { &vop_create_desc, spec_create }, /* create */ 859 { &vop_mknod_desc, spec_mknod }, /* mknod */ 860 { &vop_open_desc, spec_open }, /* open */ 861 { &vop_close_desc, spec_close }, /* close */ 862 { &vop_access_desc, efs_access }, /* access */ 863 { &vop_getattr_desc, efs_getattr }, /* getattr */ 864 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 865 { &vop_read_desc, spec_read }, /* read */ 866 { &vop_write_desc, spec_write }, /* write */ 867 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 868 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 869 { &vop_poll_desc, spec_poll }, /* poll */ 870 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 871 { &vop_revoke_desc, spec_revoke }, /* revoke */ 872 { &vop_mmap_desc, spec_mmap }, /* mmap */ 873 { &vop_fsync_desc, spec_fsync }, /* fsync */ 874 { &vop_seek_desc, spec_seek }, /* seek */ 875 { &vop_remove_desc, spec_remove }, /* remove */ 876 { &vop_link_desc, spec_link }, /* link */ 877 { &vop_rename_desc, spec_rename }, /* rename */ 878 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 879 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 880 { &vop_symlink_desc, spec_symlink }, /* symlink */ 881 { &vop_readdir_desc, spec_readdir }, /* readdir */ 882 { &vop_readlink_desc, spec_readlink }, /* readlink */ 883 { &vop_abortop_desc, spec_abortop }, /* abortop */ 884 { &vop_inactive_desc, efs_inactive }, /* inactive */ 885 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 886 { &vop_lock_desc, genfs_lock, }, /* lock */ 887 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 888 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 889 { &vop_bmap_desc, spec_bmap }, /* bmap */ 890 { &vop_print_desc, efs_print }, /* print */ 891 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 892 { &vop_advlock_desc, spec_advlock }, /* advlock */ 893 /* blkatoff */ 894 /* valloc */ 895 /* balloc */ 896 /* vfree */ 897 /* truncate */ 898 /* whiteout */ 899 { &vop_getpages_desc, spec_getpages }, /* getpages */ 900 { &vop_putpages_desc, spec_putpages }, /* putpages */ 901 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 902 { &vop_strategy_desc, spec_strategy }, /* strategy */ 903 { NULL, NULL } 904 }; 905 const struct vnodeopv_desc efs_specop_opv_desc = { 906 &efs_specop_p, 907 efs_specop_entries 908 }; 909 910 int (**efs_fifoop_p)(void *); 911 const struct vnodeopv_entry_desc efs_fifoop_entries[] = { 912 { &vop_default_desc, vn_default_error}, /* error handler */ 913 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 914 { &vop_create_desc, fifo_create }, /* create */ 915 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 916 { &vop_open_desc, fifo_open }, /* open */ 917 { &vop_close_desc, fifo_close }, /* close */ 918 { &vop_access_desc, efs_access }, /* access */ 919 { &vop_getattr_desc, efs_getattr }, /* getattr */ 920 { &vop_setattr_desc, genfs_eopnotsupp}, /* setattr */ 921 { &vop_read_desc, fifo_read }, /* read */ 922 { &vop_write_desc, fifo_write }, /* write */ 923 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 924 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 925 { &vop_poll_desc, fifo_poll }, /* poll */ 926 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 927 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 928 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 929 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 930 { &vop_seek_desc, fifo_seek }, /* seek */ 931 { &vop_remove_desc, fifo_remove }, /* remove */ 932 { &vop_link_desc, fifo_link }, /* link */ 933 { &vop_rename_desc, fifo_rename }, /* rename */ 934 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 935 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 936 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 937 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 938 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 939 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 940 { &vop_inactive_desc, efs_inactive }, /* inactive */ 941 { &vop_reclaim_desc, efs_reclaim }, /* reclaim */ 942 { &vop_lock_desc, genfs_lock, }, /* lock */ 943 { &vop_unlock_desc, genfs_unlock, }, /* unlock */ 944 { &vop_islocked_desc, genfs_islocked, }, /* islocked */ 945 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 946 { &vop_print_desc, efs_print }, /* print */ 947 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 948 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 949 /* blkatoff */ 950 /* valloc */ 951 /* balloc */ 952 /* vfree */ 953 /* truncate */ 954 /* whiteout */ 955 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 956 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 957 { NULL, NULL } 958 }; 959 const struct vnodeopv_desc efs_fifoop_opv_desc = { 960 &efs_fifoop_p, 961 efs_fifoop_entries 962 }; 963