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