1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * All rights reserved. 5 * 6 * This code is derived from software donated to Berkeley by 7 * Jan-Simon Pendry. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)portal_vnops.c 8.1 (Berkeley) 06/10/93 12 * 13 * $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $ 14 */ 15 16 /* 17 * Portal Filesystem 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/types.h> 24 #include <sys/time.h> 25 #include <sys/proc.h> 26 #include <sys/filedesc.h> 27 #include <sys/vnode.h> 28 #include <sys/file.h> 29 #include <sys/stat.h> 30 #include <sys/mount.h> 31 #include <sys/malloc.h> 32 #include <sys/namei.h> 33 #include <sys/mbuf.h> 34 #include <sys/socket.h> 35 #include <sys/socketvar.h> 36 #include <sys/un.h> 37 #include <sys/unpcb.h> 38 #include <miscfs/portal/portal.h> 39 40 static int portal_fileid = PORTAL_ROOTFILEID+1; 41 42 static void 43 portal_closefd(p, fd) 44 struct proc *p; 45 int fd; 46 { 47 int error; 48 struct { 49 int fd; 50 } ua; 51 int rc; 52 53 ua.fd = fd; 54 error = close(p, &ua, &rc); 55 /* 56 * We should never get an error, and there isn't anything 57 * we could do if we got one, so just print a message. 58 */ 59 if (error) 60 printf("portal_closefd: error = %d\n", error); 61 } 62 63 /* 64 * vp is the current namei directory 65 * cnp is the name to locate in that directory... 66 */ 67 portal_lookup(ap) 68 struct vop_lookup_args /* { 69 struct vnode * a_dvp; 70 struct vnode ** a_vpp; 71 struct componentname * a_cnp; 72 } */ *ap; 73 { 74 char *pname = ap->a_cnp->cn_nameptr; 75 struct portalnode *pt; 76 int error; 77 struct vnode *fvp = 0; 78 char *path; 79 int size; 80 81 #ifdef PORTAL_DIAGNOSTIC 82 printf("portal_lookup(%s)\n", pname); 83 #endif 84 if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 85 *ap->a_vpp = ap->a_dvp; 86 VREF(ap->a_dvp); 87 /*VOP_LOCK(ap->a_dvp);*/ 88 return (0); 89 } 90 91 92 #ifdef PORTAL_DIAGNOSTIC 93 printf("portal_lookup: allocate new vnode\n"); 94 #endif 95 error = getnewvnode(VT_UFS, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp); 96 if (error) 97 goto bad; 98 fvp->v_type = VREG; 99 MALLOC(fvp->v_data, void *, sizeof(struct portalnode), 100 M_TEMP, M_WAITOK); 101 102 pt = VTOPORTAL(fvp); 103 /* 104 * Save all of the remaining pathname and 105 * advance the namei next pointer to the end 106 * of the string. 107 */ 108 for (size = 0, path = pname; *path; path++) 109 size++; 110 ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen; 111 112 pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK); 113 pt->pt_size = size+1; 114 bcopy(pname, pt->pt_arg, pt->pt_size); 115 pt->pt_fileid = portal_fileid++; 116 117 *ap->a_vpp = fvp; 118 /*VOP_LOCK(fvp);*/ 119 #ifdef PORTAL_DIAGNOSTIC 120 printf("portal_lookup: newvp = %x\n", fvp); 121 #endif 122 return (0); 123 124 bad:; 125 if (fvp) { 126 #ifdef PORTAL_DIAGNOSTIC 127 printf("portal_lookup: vrele(%x)\n", fvp); 128 #endif 129 vrele(fvp); 130 } 131 *ap->a_vpp = NULL; 132 #ifdef PORTAL_DIAGNOSTIC 133 printf("portal_lookup: error = %d\n", error); 134 #endif 135 return (error); 136 } 137 138 static int 139 portal_connect(so, so2) 140 struct socket *so; 141 struct socket *so2; 142 { 143 /* from unp_connect, bypassing the namei stuff... */ 144 145 struct socket *so3; 146 struct unpcb *unp2; 147 struct unpcb *unp3; 148 149 #ifdef PORTAL_DIAGNOSTIC 150 printf("portal_connect\n"); 151 #endif 152 153 if (so2 == 0) 154 return (ECONNREFUSED); 155 156 if (so->so_type != so2->so_type) 157 return (EPROTOTYPE); 158 159 if ((so2->so_options & SO_ACCEPTCONN) == 0) 160 return (ECONNREFUSED); 161 162 #ifdef PORTAL_DIAGNOSTIC 163 printf("portal_connect: calling sonewconn\n"); 164 #endif 165 166 if ((so3 = sonewconn(so2, 0)) == 0) 167 return (ECONNREFUSED); 168 169 unp2 = sotounpcb(so2); 170 unp3 = sotounpcb(so3); 171 if (unp2->unp_addr) 172 unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 173 174 so2 = so3; 175 176 #ifdef PORTAL_DIAGNOSTIC 177 printf("portal_connect: calling unp_connect2\n"); 178 #endif 179 180 return (unp_connect2(so, so2)); 181 } 182 183 portal_open(ap) 184 struct vop_open_args /* { 185 struct vnode *a_vp; 186 int a_mode; 187 struct ucred *a_cred; 188 struct proc *a_p; 189 } */ *ap; 190 { 191 struct socket *so = 0; 192 struct portalnode *pt; 193 struct proc *p = ap->a_p; 194 struct vnode *vp = ap->a_vp; 195 int s; 196 struct uio auio; 197 struct iovec aiov[2]; 198 int res; 199 struct mbuf *cm = 0; 200 struct cmsghdr *cmsg; 201 int newfds; 202 int *ip; 203 int fd; 204 int error; 205 int len; 206 struct portalmount *fmp; 207 struct file *fp; 208 struct portal_cred pcred; 209 210 /* 211 * Nothing to do when opening the root node. 212 */ 213 if (vp->v_flag & VROOT) 214 return (0); 215 216 #ifdef PORTAL_DIAGNOSTIC 217 printf("portal_open(%x)\n", vp); 218 #endif 219 220 /* 221 * Can't be opened unless the caller is set up 222 * to deal with the side effects. Check for this 223 * by testing whether the p_dupfd has been set. 224 */ 225 if (p->p_dupfd >= 0) 226 return (ENODEV); 227 228 pt = VTOPORTAL(vp); 229 fmp = VFSTOPORTAL(vp->v_mount); 230 231 /* 232 * Create a new socket. 233 */ 234 error = socreate(AF_UNIX, &so, SOCK_STREAM, 0); 235 if (error) 236 goto bad; 237 238 /* 239 * Reserve some buffer space 240 */ 241 #ifdef PORTAL_DIAGNOSTIC 242 printf("portal_open: calling soreserve\n"); 243 #endif 244 res = pt->pt_size + sizeof(pcred) + 512; /* XXX */ 245 error = soreserve(so, res, res); 246 if (error) 247 goto bad; 248 249 /* 250 * Kick off connection 251 */ 252 #ifdef PORTAL_DIAGNOSTIC 253 printf("portal_open: calling portal_connect\n"); 254 #endif 255 error = portal_connect(so, (struct socket *)fmp->pm_server->f_data); 256 if (error) 257 goto bad; 258 259 /* 260 * Wait for connection to complete 261 */ 262 #ifdef PORTAL_DIAGNOSTIC 263 printf("portal_open: waiting for connect\n"); 264 #endif 265 /* 266 * XXX: Since the mount point is holding a reference on the 267 * underlying server socket, it is not easy to find out whether 268 * the server process is still running. To handle this problem 269 * we loop waiting for the new socket to be connected (something 270 * which will only happen if the server is still running) or for 271 * the reference count on the server socket to drop to 1, which 272 * will happen if the server dies. Sleep for 5 second intervals 273 * and keep polling the reference count. XXX. 274 */ 275 s = splnet(); 276 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 277 if (fmp->pm_server->f_count == 1) { 278 error = ECONNREFUSED; 279 splx(s); 280 #ifdef PORTAL_DIAGNOSTIC 281 printf("portal_open: server process has gone away\n"); 282 #endif 283 goto bad; 284 } 285 (void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz); 286 } 287 splx(s); 288 289 if (so->so_error) { 290 error = so->so_error; 291 goto bad; 292 } 293 294 /* 295 * Set miscellaneous flags 296 */ 297 so->so_rcv.sb_timeo = 0; 298 so->so_snd.sb_timeo = 0; 299 so->so_rcv.sb_flags |= SB_NOINTR; 300 so->so_snd.sb_flags |= SB_NOINTR; 301 302 #ifdef PORTAL_DIAGNOSTIC 303 printf("portal_open: constructing data uio\n"); 304 #endif 305 306 pcred.pcr_flag = ap->a_mode; 307 pcred.pcr_uid = ap->a_cred->cr_uid; 308 pcred.pcr_ngroups = ap->a_cred->cr_ngroups; 309 bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t)); 310 aiov[0].iov_base = (caddr_t) &pcred; 311 aiov[0].iov_len = sizeof(pcred); 312 aiov[1].iov_base = pt->pt_arg; 313 aiov[1].iov_len = pt->pt_size; 314 auio.uio_iov = aiov; 315 auio.uio_iovcnt = 2; 316 auio.uio_rw = UIO_WRITE; 317 auio.uio_segflg = UIO_SYSSPACE; 318 auio.uio_procp = p; 319 auio.uio_offset = 0; 320 auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len; 321 322 #ifdef PORTAL_DIAGNOSTIC 323 printf("portal_open: sending data to server\n"); 324 #endif 325 error = sosend(so, (struct sockaddr *) 0, &auio, 326 (struct mbuf *) 0, (struct mbuf *) 0, 0); 327 if (error) 328 goto bad; 329 330 len = auio.uio_resid = sizeof(int); 331 do { 332 struct mbuf *m = 0; 333 int flags = MSG_WAITALL; 334 #ifdef PORTAL_DIAGNOSTIC 335 printf("portal_open: receiving data from server\n"); 336 printf("portal_open: so = %x, cm = %x, resid = %d\n", 337 so, cm, auio.uio_resid); 338 printf("portal_open, uio=%x, mp0=%x, controlp=%x\n", &auio, &cm); 339 #endif 340 error = soreceive(so, (struct mbuf **) 0, &auio, 341 &m, &cm, &flags); 342 #ifdef PORTAL_DIAGNOSTIC 343 printf("portal_open: after receiving data\n"); 344 printf("portal_open: so = %x, cm = %x, resid = %d\n", 345 so, cm, auio.uio_resid); 346 #endif 347 if (error) 348 goto bad; 349 350 /* 351 * Grab an error code from the mbuf. 352 */ 353 if (m) { 354 m = m_pullup(m, sizeof(int)); /* Needed? */ 355 if (m) { 356 error = *(mtod(m, int *)); 357 m_freem(m); 358 } else { 359 error = EINVAL; 360 } 361 #ifdef PORTAL_DIAGNOSTIC 362 printf("portal_open: error returned is %d\n", error); 363 #endif 364 } else { 365 if (cm == 0) { 366 #ifdef PORTAL_DIAGNOSTIC 367 printf("portal_open: no rights received\n"); 368 #endif 369 error = ECONNRESET; /* XXX */ 370 #ifdef notdef 371 break; 372 #endif 373 } 374 } 375 } while (cm == 0 && auio.uio_resid == len && !error); 376 377 if (cm == 0) 378 goto bad; 379 380 if (auio.uio_resid) { 381 #ifdef PORTAL_DIAGNOSTIC 382 printf("portal_open: still need another %d bytes\n", auio.uio_resid); 383 #endif 384 error = 0; 385 #ifdef notdef 386 error = EMSGSIZE; 387 goto bad; 388 #endif 389 } 390 391 /* 392 * XXX: Break apart the control message, and retrieve the 393 * received file descriptor. Note that more than one descriptor 394 * may have been received, or that the rights chain may have more 395 * than a single mbuf in it. What to do? 396 */ 397 #ifdef PORTAL_DIAGNOSTIC 398 printf("portal_open: about to break apart control message\n"); 399 #endif 400 cmsg = mtod(cm, struct cmsghdr *); 401 newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int); 402 if (newfds == 0) { 403 #ifdef PORTAL_DIAGNOSTIC 404 printf("portal_open: received no fds\n"); 405 #endif 406 error = ECONNREFUSED; 407 goto bad; 408 } 409 /* 410 * At this point the rights message consists of a control message 411 * header, followed by a data region containing a vector of 412 * integer file descriptors. The fds were allocated by the action 413 * of receiving the control message. 414 */ 415 ip = (int *) (cmsg + 1); 416 fd = *ip++; 417 if (newfds > 1) { 418 /* 419 * Close extra fds. 420 */ 421 int i; 422 printf("portal_open: %d extra fds\n", newfds - 1); 423 for (i = 1; i < newfds; i++) { 424 portal_closefd(p, *ip); 425 ip++; 426 } 427 } 428 429 /* 430 * Check that the mode the file is being opened for is a subset 431 * of the mode of the existing descriptor. 432 */ 433 #ifdef PORTAL_DIAGNOSTIC 434 printf("portal_open: checking file flags, fd = %d\n", fd); 435 #endif 436 fp = p->p_fd->fd_ofiles[fd]; 437 if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { 438 portal_closefd(p, fd); 439 error = EACCES; 440 goto bad; 441 } 442 443 #ifdef PORTAL_DIAGNOSTIC 444 printf("portal_open: got fd = %d\n", fd); 445 #endif 446 /* 447 * Save the dup fd in the proc structure then return the 448 * special error code (ENXIO) which causes magic things to 449 * happen in vn_open. The whole concept is, well, hmmm. 450 */ 451 p->p_dupfd = fd; 452 error = ENXIO; 453 454 bad:; 455 /* 456 * And discard the control message. 457 */ 458 if (cm) { 459 #ifdef PORTAL_DIAGNOSTIC 460 printf("portal_open: free'ing control message\n"); 461 #endif 462 m_freem(cm); 463 } 464 465 if (so) { 466 #ifdef PORTAL_DIAGNOSTIC 467 printf("portal_open: calling soshutdown\n"); 468 #endif 469 soshutdown(so, 2); 470 #ifdef PORTAL_DIAGNOSTIC 471 printf("portal_open: calling soclose\n"); 472 #endif 473 soclose(so); 474 } 475 #ifdef PORTAL_DIAGNOSTIC 476 if (error != ENODEV) 477 printf("portal_open: error = %d\n", error); 478 #endif 479 return (error); 480 } 481 482 portal_getattr(ap) 483 struct vop_getattr_args /* { 484 struct vnode *a_vp; 485 struct vattr *a_vap; 486 struct ucred *a_cred; 487 struct proc *a_p; 488 } */ *ap; 489 { 490 struct vnode *vp = ap->a_vp; 491 struct vattr *vap = ap->a_vap; 492 unsigned fd; 493 int error; 494 495 bzero((caddr_t) vap, sizeof(*vap)); 496 vattr_null(vap); 497 vap->va_uid = 0; 498 vap->va_gid = 0; 499 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 500 vap->va_size = DEV_BSIZE; 501 vap->va_blocksize = DEV_BSIZE; 502 microtime(&vap->va_atime); 503 vap->va_mtime = vap->va_atime; 504 vap->va_ctime = vap->va_ctime; 505 vap->va_gen = 0; 506 vap->va_flags = 0; 507 vap->va_rdev = 0; 508 /* vap->va_qbytes = 0; */ 509 vap->va_bytes = 0; 510 /* vap->va_qsize = 0; */ 511 if (vp->v_flag & VROOT) { 512 #ifdef PORTAL_DIAGNOSTIC 513 printf("portal_getattr: stat rootdir\n"); 514 #endif 515 vap->va_type = VDIR; 516 vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR| 517 S_IRGRP|S_IWGRP|S_IXGRP| 518 S_IROTH|S_IWOTH|S_IXOTH; 519 vap->va_nlink = 2; 520 vap->va_fileid = 2; 521 } else { 522 #ifdef PORTAL_DIAGNOSTIC 523 printf("portal_getattr: stat portal\n"); 524 #endif 525 vap->va_type = VREG; 526 vap->va_mode = S_IRUSR|S_IWUSR| 527 S_IRGRP|S_IWGRP| 528 S_IROTH|S_IWOTH; 529 vap->va_nlink = 1; 530 vap->va_fileid = VTOPORTAL(vp)->pt_fileid; 531 } 532 return (0); 533 } 534 535 portal_setattr(ap) 536 struct vop_setattr_args /* { 537 struct vnode *a_vp; 538 struct vattr *a_vap; 539 struct ucred *a_cred; 540 struct proc *a_p; 541 } */ *ap; 542 { 543 /* 544 * Can't mess with the root vnode 545 */ 546 if (ap->a_vp->v_flag & VROOT) 547 return (EACCES); 548 549 return (0); 550 } 551 552 /* 553 * Fake readdir, just return empty directory. 554 * It is hard to deal with '.' and '..' so don't bother. 555 */ 556 portal_readdir(ap) 557 struct vop_readdir_args /* { 558 struct vnode *a_vp; 559 struct uio *a_uio; 560 struct ucred *a_cred; 561 } */ *ap; 562 { 563 /* *ap->a_eofflagp = 1; */ 564 return (0); 565 } 566 567 portal_inactive(ap) 568 struct vop_inactive_args /* { 569 struct vnode *a_vp; 570 } */ *ap; 571 { 572 #ifdef PORTAL_DIAGNOSTIC 573 if (VTOPORTAL(ap->a_vp)->pt_arg) 574 printf("portal_inactive(%x, %s)\n", ap->a_vp, VTOPORTAL(ap->a_vp)->pt_arg); 575 else 576 printf("portal_inactive(%x)\n", ap->a_vp); 577 #endif 578 /*vgone(ap->a_vp);*/ 579 return (0); 580 } 581 582 portal_reclaim(ap) 583 struct vop_reclaim_args /* { 584 struct vnode *a_vp; 585 } */ *ap; 586 { 587 struct portalnode *pt = VTOPORTAL(ap->a_vp); 588 #ifdef PORTAL_DIAGOISTIC 589 printf("portal_reclaim(%x)\n", ap->a_vp); 590 #endif 591 if (pt->pt_arg) { 592 free((caddr_t) pt->pt_arg, M_TEMP); 593 pt->pt_arg = 0; 594 } 595 FREE(pt, M_TEMP); 596 return (0); 597 } 598 599 /* 600 * Print out the contents of a Portal vnode. 601 */ 602 /* ARGSUSED */ 603 portal_print(ap) 604 struct vop_print_args /* { 605 struct vnode *a_vp; 606 } */ *ap; 607 { 608 609 printf("tag VT_PORTAL, portal vnode\n"); 610 return (0); 611 } 612 613 /*void*/ 614 portal_vfree(ap) 615 struct vop_vfree_args /* { 616 struct vnode *a_pvp; 617 ino_t a_ino; 618 int a_mode; 619 } */ *ap; 620 { 621 622 return (0); 623 } 624 625 626 /* 627 * Portal vnode unsupported operation 628 */ 629 portal_enotsupp() 630 { 631 632 return (EOPNOTSUPP); 633 } 634 635 /* 636 * Portal "should never get here" operation 637 */ 638 portal_badop() 639 { 640 641 panic("portal: bad op"); 642 /* NOTREACHED */ 643 } 644 645 /* 646 * Portal vnode null operation 647 */ 648 portal_nullop() 649 { 650 651 return (0); 652 } 653 654 #define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp) 655 #define portal_mknod ((int (*) __P((struct vop_mknod_args *)))portal_enotsupp) 656 #define portal_close ((int (*) __P((struct vop_close_args *)))nullop) 657 #define portal_access ((int (*) __P((struct vop_access_args *)))nullop) 658 #define portal_read ((int (*) __P((struct vop_read_args *)))portal_enotsupp) 659 #define portal_write ((int (*) __P((struct vop_write_args *)))portal_enotsupp) 660 #define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp) 661 #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp) 662 #define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp) 663 #define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 664 #define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop) 665 #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp) 666 #define portal_link ((int (*) __P((struct vop_link_args *)))portal_enotsupp) 667 #define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp) 668 #define portal_mkdir ((int (*) __P((struct vop_mkdir_args *)))portal_enotsupp) 669 #define portal_rmdir ((int (*) __P((struct vop_rmdir_args *)))portal_enotsupp) 670 #define portal_symlink \ 671 ((int (*) __P((struct vop_symlink_args *)))portal_enotsupp) 672 #define portal_readlink \ 673 ((int (*) __P((struct vop_readlink_args *)))portal_enotsupp) 674 #define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 675 #define portal_lock ((int (*) __P((struct vop_lock_args *)))nullop) 676 #define portal_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 677 #define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop) 678 #define portal_strategy \ 679 ((int (*) __P((struct vop_strategy_args *)))portal_badop) 680 #define portal_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 681 #define portal_advlock \ 682 ((int (*) __P((struct vop_advlock_args *)))portal_enotsupp) 683 #define portal_blkatoff \ 684 ((int (*) __P((struct vop_blkatoff_args *)))portal_enotsupp) 685 #define portal_valloc ((int(*) __P(( \ 686 struct vnode *pvp, \ 687 int mode, \ 688 struct ucred *cred, \ 689 struct vnode **vpp))) portal_enotsupp) 690 #define portal_truncate \ 691 ((int (*) __P((struct vop_truncate_args *)))portal_enotsupp) 692 #define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp) 693 #define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp) 694 695 int (**portal_vnodeop_p)(); 696 struct vnodeopv_entry_desc portal_vnodeop_entries[] = { 697 { &vop_default_desc, vn_default_error }, 698 { &vop_lookup_desc, portal_lookup }, /* lookup */ 699 { &vop_create_desc, portal_create }, /* create */ 700 { &vop_mknod_desc, portal_mknod }, /* mknod */ 701 { &vop_open_desc, portal_open }, /* open */ 702 { &vop_close_desc, portal_close }, /* close */ 703 { &vop_access_desc, portal_access }, /* access */ 704 { &vop_getattr_desc, portal_getattr }, /* getattr */ 705 { &vop_setattr_desc, portal_setattr }, /* setattr */ 706 { &vop_read_desc, portal_read }, /* read */ 707 { &vop_write_desc, portal_write }, /* write */ 708 { &vop_ioctl_desc, portal_ioctl }, /* ioctl */ 709 { &vop_select_desc, portal_select }, /* select */ 710 { &vop_mmap_desc, portal_mmap }, /* mmap */ 711 { &vop_fsync_desc, portal_fsync }, /* fsync */ 712 { &vop_seek_desc, portal_seek }, /* seek */ 713 { &vop_remove_desc, portal_remove }, /* remove */ 714 { &vop_link_desc, portal_link }, /* link */ 715 { &vop_rename_desc, portal_rename }, /* rename */ 716 { &vop_mkdir_desc, portal_mkdir }, /* mkdir */ 717 { &vop_rmdir_desc, portal_rmdir }, /* rmdir */ 718 { &vop_symlink_desc, portal_symlink }, /* symlink */ 719 { &vop_readdir_desc, portal_readdir }, /* readdir */ 720 { &vop_readlink_desc, portal_readlink }, /* readlink */ 721 { &vop_abortop_desc, portal_abortop }, /* abortop */ 722 { &vop_inactive_desc, portal_inactive }, /* inactive */ 723 { &vop_reclaim_desc, portal_reclaim }, /* reclaim */ 724 { &vop_lock_desc, portal_lock }, /* lock */ 725 { &vop_unlock_desc, portal_unlock }, /* unlock */ 726 { &vop_bmap_desc, portal_bmap }, /* bmap */ 727 { &vop_strategy_desc, portal_strategy }, /* strategy */ 728 { &vop_print_desc, portal_print }, /* print */ 729 { &vop_islocked_desc, portal_islocked }, /* islocked */ 730 { &vop_advlock_desc, portal_advlock }, /* advlock */ 731 { &vop_blkatoff_desc, portal_blkatoff }, /* blkatoff */ 732 { &vop_valloc_desc, portal_valloc }, /* valloc */ 733 { &vop_vfree_desc, portal_vfree }, /* vfree */ 734 { &vop_truncate_desc, portal_truncate }, /* truncate */ 735 { &vop_update_desc, portal_update }, /* update */ 736 { &vop_bwrite_desc, portal_bwrite }, /* bwrite */ 737 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 738 }; 739 struct vnodeopv_desc portal_vnodeop_opv_desc = 740 { &portal_vnodeop_p, portal_vnodeop_entries }; 741