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