1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * Copyright (c) 1990, 1992 Jan-Simon Pendry 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 7.2 (Berkeley) 07/13/92 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 int s; 194 struct uio auio; 195 struct iovec aiov[2]; 196 int res; 197 struct mbuf *cm = 0; 198 struct cmsghdr *cmsg; 199 int newfds; 200 int *ip; 201 int fd; 202 int error; 203 int len; 204 struct portalmount *fmp; 205 struct file *fp; 206 struct portal_cred pcred; 207 208 /* 209 * Nothing to do when opening the root node. 210 */ 211 if (ap->a_vp->v_flag & VROOT) 212 return (0); 213 214 #ifdef PORTAL_DIAGNOSTIC 215 printf("portal_open(%x)\n", ap->a_vp); 216 #endif 217 218 /* 219 * Can't be opened unless the caller is set up 220 * to deal with the side effects. Check for this 221 * by testing whether the p_dupfd has been set. 222 */ 223 if (ap->a_p->p_dupfd >= 0) 224 return (ENODEV); 225 226 pt = VTOPORTAL(ap->a_vp); 227 fmp = VFSTOPORTAL(ap->a_vp->v_mount); 228 229 /* 230 * Create a new socket. 231 */ 232 error = socreate(AF_UNIX, &so, SOCK_STREAM, 0); 233 if (error) 234 goto bad; 235 236 /* 237 * Reserve some buffer space 238 */ 239 #ifdef PORTAL_DIAGNOSTIC 240 printf("portal_open: calling soreserve\n"); 241 #endif 242 res = pt->pt_size + sizeof(pcred) + 512; /* XXX */ 243 error = soreserve(so, res, res); 244 if (error) 245 goto bad; 246 247 /* 248 * Kick off connection 249 */ 250 #ifdef PORTAL_DIAGNOSTIC 251 printf("portal_open: calling portal_connect\n"); 252 #endif 253 error = portal_connect(so, (struct socket *)fmp->pm_server->f_data); 254 if (error) 255 goto bad; 256 257 /* 258 * Wait for connection to complete 259 */ 260 #ifdef PORTAL_DIAGNOSTIC 261 printf("portal_open: waiting for connect\n"); 262 #endif 263 /* 264 * XXX: Since the mount point is holding a reference on the 265 * underlying server socket, it is not easy to find out whether 266 * the server process is still running. To handle this problem 267 * we loop waiting for the new socket to be connected (something 268 * which will only happen if the server is still running) or for 269 * the reference count on the server socket to drop to 1, which 270 * will happen if the server dies. Sleep for 5 second intervals 271 * and keep polling the reference count. XXX. 272 */ 273 s = splnet(); 274 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 275 if (fmp->pm_server->f_count == 1) { 276 error = ECONNREFUSED; 277 splx(s); 278 #ifdef PORTAL_DIAGNOSTIC 279 printf("portal_open: server process has gone away\n"); 280 #endif 281 goto bad; 282 } 283 (void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz); 284 } 285 splx(s); 286 287 if (so->so_error) { 288 error = so->so_error; 289 goto bad; 290 } 291 292 /* 293 * Set miscellaneous flags 294 */ 295 so->so_rcv.sb_timeo = 0; 296 so->so_snd.sb_timeo = 0; 297 so->so_rcv.sb_flags |= SB_NOINTR; 298 so->so_snd.sb_flags |= SB_NOINTR; 299 300 #ifdef PORTAL_DIAGNOSTIC 301 printf("portal_open: constructing data uio\n"); 302 #endif 303 304 pcred.pcr_flag = ap->a_mode; 305 pcred.pcr_uid = ap->a_cred->cr_uid; 306 pcred.pcr_ngroups = ap->a_cred->cr_ngroups; 307 bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t)); 308 aiov[0].iov_base = (caddr_t) &pcred; 309 aiov[0].iov_len = sizeof(pcred); 310 aiov[1].iov_base = pt->pt_arg; 311 aiov[1].iov_len = pt->pt_size; 312 auio.uio_iov = aiov; 313 auio.uio_iovcnt = 2; 314 auio.uio_rw = UIO_WRITE; 315 auio.uio_segflg = UIO_SYSSPACE; 316 auio.uio_procp = ap->a_p; 317 auio.uio_offset = 0; 318 auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len; 319 320 #ifdef PORTAL_DIAGNOSTIC 321 printf("portal_open: sending data to server\n"); 322 #endif 323 error = sosend(so, (struct sockaddr *) 0, &auio, 324 (struct mbuf *) 0, (struct mbuf *) 0, 0); 325 if (error) 326 goto bad; 327 328 len = auio.uio_resid = sizeof(int); 329 do { 330 struct mbuf *m = 0; 331 int flags = MSG_WAITALL; 332 #ifdef PORTAL_DIAGNOSTIC 333 printf("portal_open: receiving data from server\n"); 334 printf("portal_open: so = %x, cm = %x, resid = %d\n", 335 so, cm, auio.uio_resid); 336 printf("portal_open, uio=%x, mp0=%x, controlp=%x\n", &auio, &cm); 337 #endif 338 error = soreceive(so, (struct mbuf **) 0, &auio, 339 &m, &cm, &flags); 340 #ifdef PORTAL_DIAGNOSTIC 341 printf("portal_open: after receiving data\n"); 342 printf("portal_open: so = %x, cm = %x, resid = %d\n", 343 so, cm, auio.uio_resid); 344 #endif 345 if (error) 346 goto bad; 347 348 /* 349 * Grab an error code from the mbuf. 350 */ 351 if (m) { 352 m = m_pullup(m, sizeof(int)); /* Needed? */ 353 if (m) { 354 error = *(mtod(m, int *)); 355 m_freem(m); 356 } else { 357 error = EINVAL; 358 } 359 #ifdef PORTAL_DIAGNOSTIC 360 printf("portal_open: error returned is %d\n", error); 361 #endif 362 } else { 363 if (cm == 0) { 364 #ifdef PORTAL_DIAGNOSTIC 365 printf("portal_open: no rights received\n"); 366 #endif 367 error = ECONNRESET; /* XXX */ 368 #ifdef notdef 369 break; 370 #endif 371 } 372 } 373 } while (cm == 0 && auio.uio_resid == len && !error); 374 375 if (cm == 0) 376 goto bad; 377 378 if (auio.uio_resid) { 379 #ifdef PORTAL_DIAGNOSTIC 380 printf("portal_open: still need another %d bytes\n", auio.uio_resid); 381 #endif 382 error = 0; 383 #ifdef notdef 384 error = EMSGSIZE; 385 goto bad; 386 #endif 387 } 388 389 /* 390 * XXX: Break apart the control message, and retrieve the 391 * received file descriptor. Note that more than one descriptor 392 * may have been received, or that the rights chain may have more 393 * than a single mbuf in it. What to do? 394 */ 395 #ifdef PORTAL_DIAGNOSTIC 396 printf("portal_open: about to break apart control message\n"); 397 #endif 398 cmsg = mtod(cm, struct cmsghdr *); 399 newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int); 400 if (newfds == 0) { 401 #ifdef PORTAL_DIAGNOSTIC 402 printf("portal_open: received no fds\n"); 403 #endif 404 error = ECONNREFUSED; 405 goto bad; 406 } 407 /* 408 * At this point the rights message consists of a control message 409 * header, followed by a data region containing a vector of 410 * integer file descriptors. The fds were allocated by the action 411 * of receiving the control message. 412 */ 413 ip = (int *) (cmsg + 1); 414 fd = *ip++; 415 if (newfds > 1) { 416 /* 417 * Close extra fds. 418 */ 419 int i; 420 printf("portal_open: %d extra fds\n", newfds - 1); 421 for (i = 1; i < newfds; i++) { 422 portal_closefd(ap->a_p, *ip); 423 ip++; 424 } 425 } 426 427 /* 428 * Check that the ap->a_mode the file is being opened for is a subset 429 * of the ap->a_mode of the existing descriptor. 430 */ 431 #ifdef PORTAL_DIAGNOSTIC 432 printf("portal_open: checking file flags, fd = %d\n", fd); 433 #endif 434 fp = ap->a_p->p_fd->fd_ofiles[fd]; 435 if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { 436 portal_closefd(ap->a_p, fd); 437 error = EACCES; 438 goto bad; 439 } 440 441 #ifdef PORTAL_DIAGNOSTIC 442 printf("portal_open: got fd = %d\n", fd); 443 #endif 444 /* 445 * Save the dup fd in the proc structure then return the 446 * special error code (ENXIO) which causes magic things to 447 * happen in vn_open. The whole concept is, well, hmmm. 448 */ 449 ap->a_p->p_dupfd = fd; 450 error = ENXIO; 451 452 bad:; 453 /* 454 * And discard the control message. 455 */ 456 if (cm) { 457 #ifdef PORTAL_DIAGNOSTIC 458 printf("portal_open: free'ing control message\n"); 459 #endif 460 m_freem(cm); 461 } 462 463 if (so) { 464 #ifdef PORTAL_DIAGNOSTIC 465 printf("portal_open: calling soshutdown\n"); 466 #endif 467 soshutdown(so, 2); 468 #ifdef PORTAL_DIAGNOSTIC 469 printf("portal_open: calling soclose\n"); 470 #endif 471 soclose(so); 472 } 473 #ifdef PORTAL_DIAGNOSTIC 474 if (error != ENODEV) 475 printf("portal_open: error = %d\n", error); 476 #endif 477 return (error); 478 } 479 480 portal_getattr(ap) 481 struct vop_getattr_args /* { 482 struct vnode *a_vp; 483 struct vattr *a_vap; 484 struct ucred *a_cred; 485 struct proc *a_p; 486 } */ *ap; 487 { 488 unsigned fd; 489 int error; 490 491 bzero((caddr_t) ap->a_vap, sizeof(*ap->a_vap)); 492 vattr_null(ap->a_vap); 493 ap->a_vap->va_uid = 0; 494 ap->a_vap->va_gid = 0; 495 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 496 ap->a_vap->va_size = DEV_BSIZE; 497 ap->a_vap->va_blocksize = DEV_BSIZE; 498 microtime(&ap->a_vap->va_atime); 499 ap->a_vap->va_mtime = ap->a_vap->va_atime; 500 ap->a_vap->va_ctime = ap->a_vap->va_ctime; 501 ap->a_vap->va_gen = 0; 502 ap->a_vap->va_flags = 0; 503 ap->a_vap->va_rdev = 0; 504 /* ap->a_vap->va_qbytes = 0; */ 505 ap->a_vap->va_bytes = 0; 506 /* ap->a_vap->va_qsize = 0; */ 507 if (ap->a_vp->v_flag & VROOT) { 508 #ifdef PORTAL_DIAGNOSTIC 509 printf("portal_getattr: stat rootdir\n"); 510 #endif 511 ap->a_vap->va_type = VDIR; 512 ap->a_vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR| 513 S_IRGRP|S_IWGRP|S_IXGRP| 514 S_IROTH|S_IWOTH|S_IXOTH; 515 ap->a_vap->va_nlink = 2; 516 ap->a_vap->va_fileid = 2; 517 } else { 518 #ifdef PORTAL_DIAGNOSTIC 519 printf("portal_getattr: stat portal\n"); 520 #endif 521 ap->a_vap->va_type = VREG; 522 ap->a_vap->va_mode = S_IRUSR|S_IWUSR| 523 S_IRGRP|S_IWGRP| 524 S_IROTH|S_IWOTH; 525 ap->a_vap->va_nlink = 1; 526 ap->a_vap->va_fileid = VTOPORTAL(ap->a_vp)->pt_fileid; 527 } 528 return (0); 529 } 530 531 portal_setattr(ap) 532 struct vop_setattr_args /* { 533 struct vnode *a_vp; 534 struct vattr *a_vap; 535 struct ucred *a_cred; 536 struct proc *a_p; 537 } */ *ap; 538 { 539 /* 540 * Can't mess with the root vnode 541 */ 542 if (ap->a_vp->v_flag & VROOT) 543 return (EACCES); 544 545 return (0); 546 } 547 548 /* 549 * Fake readdir, just return empty directory. 550 * It is hard to deal with '.' and '..' so don't bother. 551 */ 552 portal_readdir(ap) 553 struct vop_readdir_args /* { 554 struct vnode *a_vp; 555 struct uio *a_uio; 556 struct ucred *a_cred; 557 } */ *ap; 558 { 559 /* *ap->a_eofflagp = 1; */ 560 return (0); 561 } 562 563 portal_inactive(ap) 564 struct vop_inactive_args /* { 565 struct vnode *a_vp; 566 } */ *ap; 567 { 568 #ifdef PORTAL_DIAGNOSTIC 569 if (VTOPORTAL(ap->a_vp)->pt_arg) 570 printf("portal_inactive(%x, %s)\n", ap->a_vp, VTOPORTAL(ap->a_vp)->pt_arg); 571 else 572 printf("portal_inactive(%x)\n", ap->a_vp); 573 #endif 574 /*vgone(ap->a_vp);*/ 575 return (0); 576 } 577 578 portal_reclaim(ap) 579 struct vop_reclaim_args /* { 580 struct vnode *a_vp; 581 } */ *ap; 582 { 583 struct portalnode *pt = VTOPORTAL(ap->a_vp); 584 #ifdef PORTAL_DIAGOISTIC 585 printf("portal_reclaim(%x)\n", ap->a_vp); 586 #endif 587 if (pt->pt_arg) { 588 free((caddr_t) pt->pt_arg, M_TEMP); 589 pt->pt_arg = 0; 590 } 591 FREE(pt, M_TEMP); 592 return (0); 593 } 594 595 /* 596 * Print out the contents of a Portal vnode. 597 */ 598 /* ARGSUSED */ 599 portal_print(ap) 600 struct vop_print_args /* { 601 struct vnode *a_vp; 602 } */ *ap; 603 { 604 605 printf("tag VT_PORTAL, portal vnode\n"); 606 return (0); 607 } 608 609 /*void*/ 610 portal_vfree(ap) 611 struct vop_vfree_args /* { 612 struct vnode *a_pvp; 613 ino_t a_ino; 614 int a_mode; 615 } */ *ap; 616 { 617 618 return (0); 619 } 620 621 622 /* 623 * Portal vnode unsupported operation 624 */ 625 portal_enotsupp() 626 { 627 628 return (EOPNOTSUPP); 629 } 630 631 /* 632 * Portal "should never get here" operation 633 */ 634 portal_badop() 635 { 636 637 panic("portal: bad op"); 638 /* NOTREACHED */ 639 } 640 641 /* 642 * Portal vnode null operation 643 */ 644 portal_nullop() 645 { 646 647 return (0); 648 } 649 650 #define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp) 651 #define portal_mknod ((int (*) __P((struct vop_mknod_args *)))portal_enotsupp) 652 #define portal_close ((int (*) __P((struct vop_close_args *)))nullop) 653 #define portal_access ((int (*) __P((struct vop_access_args *)))nullop) 654 #define portal_read ((int (*) __P((struct vop_read_args *)))portal_enotsupp) 655 #define portal_write ((int (*) __P((struct vop_write_args *)))portal_enotsupp) 656 #define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp) 657 #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp) 658 #define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp) 659 #define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 660 #define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop) 661 #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp) 662 #define portal_link ((int (*) __P((struct vop_link_args *)))portal_enotsupp) 663 #define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp) 664 #define portal_mkdir ((int (*) __P((struct vop_mkdir_args *)))portal_enotsupp) 665 #define portal_rmdir ((int (*) __P((struct vop_rmdir_args *)))portal_enotsupp) 666 #define portal_symlink \ 667 ((int (*) __P((struct vop_symlink_args *)))portal_enotsupp) 668 #define portal_readlink \ 669 ((int (*) __P((struct vop_readlink_args *)))portal_enotsupp) 670 #define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 671 #define portal_lock ((int (*) __P((struct vop_lock_args *)))nullop) 672 #define portal_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 673 #define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop) 674 #define portal_strategy \ 675 ((int (*) __P((struct vop_strategy_args *)))portal_badop) 676 #define portal_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 677 #define portal_advlock \ 678 ((int (*) __P((struct vop_advlock_args *)))portal_enotsupp) 679 #define portal_blkatoff \ 680 ((int (*) __P((struct vop_blkatoff_args *)))portal_enotsupp) 681 #define portal_valloc ((int(*) __P(( \ 682 struct vnode *pvp, \ 683 int mode, \ 684 struct ucred *cred, \ 685 struct vnode **vpp))) portal_enotsupp) 686 #define portal_truncate \ 687 ((int (*) __P((struct vop_truncate_args *)))portal_enotsupp) 688 #define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp) 689 #define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp) 690 691 int (**portal_vnodeop_p)(); 692 struct vnodeopv_entry_desc portal_vnodeop_entries[] = { 693 { &vop_default_desc, vn_default_error }, 694 { &vop_lookup_desc, portal_lookup }, /* lookup */ 695 { &vop_create_desc, portal_create }, /* create */ 696 { &vop_mknod_desc, portal_mknod }, /* mknod */ 697 { &vop_open_desc, portal_open }, /* open */ 698 { &vop_close_desc, portal_close }, /* close */ 699 { &vop_access_desc, portal_access }, /* access */ 700 { &vop_getattr_desc, portal_getattr }, /* getattr */ 701 { &vop_setattr_desc, portal_setattr }, /* setattr */ 702 { &vop_read_desc, portal_read }, /* read */ 703 { &vop_write_desc, portal_write }, /* write */ 704 { &vop_ioctl_desc, portal_ioctl }, /* ioctl */ 705 { &vop_select_desc, portal_select }, /* select */ 706 { &vop_mmap_desc, portal_mmap }, /* mmap */ 707 { &vop_fsync_desc, portal_fsync }, /* fsync */ 708 { &vop_seek_desc, portal_seek }, /* seek */ 709 { &vop_remove_desc, portal_remove }, /* remove */ 710 { &vop_link_desc, portal_link }, /* link */ 711 { &vop_rename_desc, portal_rename }, /* rename */ 712 { &vop_mkdir_desc, portal_mkdir }, /* mkdir */ 713 { &vop_rmdir_desc, portal_rmdir }, /* rmdir */ 714 { &vop_symlink_desc, portal_symlink }, /* symlink */ 715 { &vop_readdir_desc, portal_readdir }, /* readdir */ 716 { &vop_readlink_desc, portal_readlink }, /* readlink */ 717 { &vop_abortop_desc, portal_abortop }, /* abortop */ 718 { &vop_inactive_desc, portal_inactive }, /* inactive */ 719 { &vop_reclaim_desc, portal_reclaim }, /* reclaim */ 720 { &vop_lock_desc, portal_lock }, /* lock */ 721 { &vop_unlock_desc, portal_unlock }, /* unlock */ 722 { &vop_bmap_desc, portal_bmap }, /* bmap */ 723 { &vop_strategy_desc, portal_strategy }, /* strategy */ 724 { &vop_print_desc, portal_print }, /* print */ 725 { &vop_islocked_desc, portal_islocked }, /* islocked */ 726 { &vop_advlock_desc, portal_advlock }, /* advlock */ 727 { &vop_blkatoff_desc, portal_blkatoff }, /* blkatoff */ 728 { &vop_valloc_desc, portal_valloc }, /* valloc */ 729 { &vop_vfree_desc, portal_vfree }, /* vfree */ 730 { &vop_truncate_desc, portal_truncate }, /* truncate */ 731 { &vop_update_desc, portal_update }, /* update */ 732 { &vop_bwrite_desc, portal_bwrite }, /* bwrite */ 733 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 734 }; 735 struct vnodeopv_desc portal_vnodeop_opv_desc = 736 { &portal_vnodeop_p, portal_vnodeop_entries }; 737