root/miscfs/portal/portal_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. portal_closefd
  2. portal_lookup
  3. portal_connect
  4. portal_open
  5. portal_getattr
  6. portal_setattr
  7. portal_readdir
  8. portal_inactive
  9. portal_reclaim
  10. portal_pathconf
  11. portal_print
  12. portal_link
  13. portal_symlink
  14. portal_badop
  15. portal_poll

    1 /*      $OpenBSD: portal_vnops.c,v 1.24 2007/06/18 08:30:07 jasper Exp $        */
    2 /*      $NetBSD: portal_vnops.c,v 1.17 1996/02/13 13:12:57 mycroft Exp $        */
    3 
    4 /*
    5  * Copyright (c) 1992, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software donated to Berkeley by
    9  * Jan-Simon Pendry.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      from: Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp
   36  *      @(#)portal_vnops.c      8.8 (Berkeley) 1/21/94
   37  */
   38 
   39 /*
   40  * Portal Filesystem
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/types.h>
   47 #include <sys/time.h>
   48 #include <sys/proc.h>
   49 #include <sys/filedesc.h>
   50 #include <sys/vnode.h>
   51 #include <sys/file.h>
   52 #include <sys/stat.h>
   53 #include <sys/mount.h>
   54 #include <sys/malloc.h>
   55 #include <sys/namei.h>
   56 #include <sys/mbuf.h>
   57 #include <sys/poll.h>
   58 #include <sys/socket.h>
   59 #include <sys/socketvar.h>
   60 #include <sys/un.h>
   61 #include <sys/unpcb.h>
   62 #include <sys/syscallargs.h>
   63 #include <miscfs/portal/portal.h>
   64 
   65 static int portal_fileid = PORTAL_ROOTFILEID+1;
   66 
   67 static void     portal_closefd(struct proc *, int);
   68 static int      portal_connect(struct socket *, struct socket *);
   69 
   70 
   71 int portal_badop(void *);
   72 
   73 int     portal_lookup(void *);
   74 #define portal_create   eopnotsupp
   75 #define portal_mknod    eopnotsupp
   76 int     portal_open(void *);
   77 #define portal_close    nullop
   78 #define portal_access   nullop
   79 int     portal_getattr(void *);
   80 int     portal_setattr(void *);
   81 #define portal_read     eopnotsupp
   82 #define portal_write    eopnotsupp
   83 #define portal_ioctl    (int (*)(void *))enoioctl
   84 #define portal_fsync    nullop
   85 #define portal_remove   eopnotsupp
   86 int     portal_link(void *);
   87 #define portal_rename   eopnotsupp
   88 #define portal_mkdir    eopnotsupp
   89 #define portal_rmdir    eopnotsupp
   90 int     portal_symlink(void *);
   91 int     portal_readdir(void *);
   92 #define portal_revoke   vop_generic_revoke
   93 #define portal_readlink eopnotsupp
   94 int     portal_inactive(void *);
   95 int     portal_reclaim(void *);
   96 #define portal_lock     vop_generic_lock
   97 #define portal_unlock   vop_generic_unlock
   98 #define portal_bmap     portal_badop
   99 #define portal_strategy portal_badop
  100 int     portal_print(void *);
  101 #define portal_islocked vop_generic_islocked
  102 int     portal_pathconf(void *);
  103 #define portal_advlock  eopnotsupp
  104 #define portal_bwrite   eopnotsupp
  105 int     portal_poll(void *);
  106 
  107 int (**portal_vnodeop_p)(void *);
  108 struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
  109         { &vop_default_desc, vn_default_error },
  110         { &vop_lookup_desc, portal_lookup },            /* lookup */
  111         { &vop_create_desc, portal_create },            /* create */
  112         { &vop_mknod_desc, portal_mknod },              /* mknod */
  113         { &vop_open_desc, portal_open },                /* open */
  114         { &vop_close_desc, portal_close },              /* close */
  115         { &vop_access_desc, portal_access },            /* access */
  116         { &vop_getattr_desc, portal_getattr },          /* getattr */
  117         { &vop_setattr_desc, portal_setattr },          /* setattr */
  118         { &vop_read_desc, portal_read },                /* read */
  119         { &vop_write_desc, portal_write },              /* write */
  120         { &vop_ioctl_desc, portal_ioctl },              /* ioctl */
  121         { &vop_poll_desc, portal_poll },                /* poll */
  122         { &vop_revoke_desc, portal_revoke },            /* revoke */
  123         { &vop_fsync_desc, portal_fsync },              /* fsync */
  124         { &vop_remove_desc, portal_remove },            /* remove */
  125         { &vop_link_desc, portal_link },                /* link */
  126         { &vop_rename_desc, portal_rename },            /* rename */
  127         { &vop_mkdir_desc, portal_mkdir },              /* mkdir */
  128         { &vop_rmdir_desc, portal_rmdir },              /* rmdir */
  129         { &vop_symlink_desc, portal_symlink },          /* symlink */
  130         { &vop_readdir_desc, portal_readdir },          /* readdir */
  131         { &vop_readlink_desc, portal_readlink },        /* readlink */
  132         { &vop_abortop_desc, vop_generic_abortop },             /* abortop */
  133         { &vop_inactive_desc, portal_inactive },        /* inactive */
  134         { &vop_reclaim_desc, portal_reclaim },          /* reclaim */
  135         { &vop_lock_desc, portal_lock },                /* lock */
  136         { &vop_unlock_desc, portal_unlock },            /* unlock */
  137         { &vop_bmap_desc, portal_bmap },                /* bmap */
  138         { &vop_strategy_desc, portal_strategy },        /* strategy */
  139         { &vop_print_desc, portal_print },              /* print */
  140         { &vop_islocked_desc, portal_islocked },        /* islocked */
  141         { &vop_pathconf_desc, portal_pathconf },        /* pathconf */
  142         { &vop_advlock_desc, portal_advlock },          /* advlock */
  143         { &vop_bwrite_desc, portal_bwrite },            /* bwrite */
  144         { NULL, NULL }
  145 };
  146 struct vnodeopv_desc portal_vnodeop_opv_desc =
  147         { &portal_vnodeop_p, portal_vnodeop_entries };
  148 
  149 static void
  150 portal_closefd(struct proc *p, int fd)
  151 {
  152         struct sys_close_args /* {
  153                 syscallarg(int) fd;
  154         } */ ua;
  155         register_t retval[2];
  156         int error;
  157 
  158         SCARG(&ua, fd) = fd;
  159         error = sys_close(p, &ua, retval);
  160         /*
  161          * We should never get an error, and there isn't anything
  162          * we could do if we got one, so just print a message.
  163          */
  164         if (error)
  165                 printf("portal_closefd: error = %d\n", error);
  166 }
  167 
  168 /*
  169  * vp is the current namei directory
  170  * cnp is the name to locate in that directory...
  171  */
  172 int
  173 portal_lookup(void *v)
  174 {
  175         struct vop_lookup_args *ap = v;
  176         struct componentname *cnp = ap->a_cnp;
  177         struct vnode **vpp = ap->a_vpp;
  178         struct vnode *dvp = ap->a_dvp;
  179         char *pname = cnp->cn_nameptr;
  180         struct proc *p = cnp->cn_proc;
  181         struct portalnode *pt;
  182         int error;
  183         struct vnode *fvp = 0;
  184         char *path;
  185         int size;
  186 
  187         *vpp = NULLVP;
  188 
  189         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  190                 return (EROFS);
  191 
  192         if (cnp->cn_namelen == 1 && *pname == '.') {
  193                 *vpp = dvp;
  194                 VREF(dvp);
  195                 return (0);
  196         }
  197 
  198         error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
  199         if (error)
  200                 goto bad;
  201         fvp->v_type = VREG;
  202         MALLOC(fvp->v_data, void *, sizeof(struct portalnode), M_TEMP,
  203             M_WAITOK);
  204 
  205         pt = VTOPORTAL(fvp);
  206         /*
  207          * Save all of the remaining pathname and
  208          * advance the namei next pointer to the end
  209          * of the string.
  210          */
  211         for (size = 0, path = pname; *path; path++)
  212                 size++;
  213         cnp->cn_consume = size - cnp->cn_namelen;
  214 
  215         pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
  216         pt->pt_size = size+1;
  217         bcopy(pname, pt->pt_arg, pt->pt_size);
  218         pt->pt_fileid = portal_fileid++;
  219 
  220         *vpp = fvp;
  221         VOP_LOCK(fvp, LK_EXCLUSIVE, p);
  222         /*
  223          * As we are the last component of the path name, fix up
  224          * the locking on the directory node.
  225          */
  226         if ((cnp->cn_flags & LOCKPARENT) == 0) {
  227                 VOP_UNLOCK(dvp, 0, p);
  228                 cnp->cn_flags |= PDIRUNLOCK;
  229         }
  230         return (0);
  231 
  232 bad:;
  233         if (fvp)
  234                 vrele(fvp);
  235         return (error);
  236 }
  237 
  238 static int
  239 portal_connect(struct socket *so, struct socket *so2)
  240 {
  241         /* from unp_connect, bypassing the namei stuff... */
  242         struct socket *so3;
  243         struct unpcb *unp2;
  244         struct unpcb *unp3;
  245 
  246         if (so2 == 0)
  247                 return (ECONNREFUSED);
  248 
  249         if (so->so_type != so2->so_type)
  250                 return (EPROTOTYPE);
  251 
  252         if ((so2->so_options & SO_ACCEPTCONN) == 0)
  253                 return (ECONNREFUSED);
  254 
  255         if ((so3 = sonewconn(so2, 0)) == 0)
  256                 return (ECONNREFUSED);
  257 
  258         unp2 = sotounpcb(so2);
  259         unp3 = sotounpcb(so3);
  260         if (unp2->unp_addr)
  261                 unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
  262 
  263         so2 = so3;
  264 
  265 
  266         return (unp_connect2(so, so2));
  267 }
  268 
  269 int
  270 portal_open(void *v)
  271 {
  272         struct vop_open_args *ap = v;
  273         struct socket *so = 0;
  274         struct portalnode *pt;
  275         struct proc *p = ap->a_p;
  276         struct vnode *vp = ap->a_vp;
  277         int s;
  278         struct uio auio;
  279         struct iovec aiov[2];
  280         int res;
  281         struct mbuf *cm = 0;
  282         struct cmsghdr *cmsg;
  283         int newfds;
  284         int *ip;
  285         int fd;
  286         int error;
  287         int len;
  288         struct portalmount *fmp;
  289         struct file *fp;
  290         struct portal_cred pcred;
  291 
  292         /*
  293          * Nothing to do when opening the root node.
  294          */
  295         if (vp->v_flag & VROOT)
  296                 return (0);
  297 
  298         /*
  299          * Can't be opened unless the caller is set up
  300          * to deal with the side effects.  Check for this
  301          * by testing whether the p_dupfd has been set.
  302          */
  303         if (p->p_dupfd >= 0)
  304                 return (ENODEV);
  305 
  306         pt = VTOPORTAL(vp);
  307         fmp = VFSTOPORTAL(vp->v_mount);
  308 
  309         /*
  310          * Create a new socket.
  311          */
  312         error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
  313         if (error)
  314                 goto bad;
  315 
  316         /*
  317          * Reserve some buffer space
  318          */
  319         res = pt->pt_size + sizeof(pcred) + 512;        /* XXX */
  320         error = soreserve(so, res, res);
  321         if (error)
  322                 goto bad;
  323 
  324         /*
  325          * Kick off connection
  326          */
  327         s = splsoftnet();
  328         error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
  329         splx(s);
  330         if (error)
  331                 goto bad;
  332 
  333         /*
  334          * Wait for connection to complete
  335          */
  336         /*
  337          * XXX: Since the mount point is holding a reference on the
  338          * underlying server socket, it is not easy to find out whether
  339          * the server process is still running.  To handle this problem
  340          * we loop waiting for the new socket to be connected (something
  341          * which will only happen if the server is still running) or for
  342          * the reference count on the server socket to drop to 1, which
  343          * will happen if the server dies.  Sleep for 5 second intervals
  344          * and keep polling the reference count.   XXX.
  345          */
  346         s = splsoftnet();
  347         while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
  348                 if (fmp->pm_server->f_count == 1) {
  349                         error = ECONNREFUSED;
  350                         splx(s);
  351                         goto bad;
  352                 }
  353                 (void) tsleep(&so->so_timeo, PSOCK, "portalcon", 5 * hz);
  354         }
  355         splx(s);
  356 
  357         if (so->so_error) {
  358                 error = so->so_error;
  359                 goto bad;
  360         }
  361                 
  362         /*
  363          * Set miscellaneous flags
  364          */
  365         so->so_rcv.sb_timeo = 0;
  366         so->so_snd.sb_timeo = 0;
  367         so->so_rcv.sb_flags |= SB_NOINTR;
  368         so->so_snd.sb_flags |= SB_NOINTR;
  369 
  370 
  371         pcred.pcr_flag = ap->a_mode;
  372         pcred.pcr_uid = ap->a_cred->cr_uid;
  373         pcred.pcr_gid = ap->a_cred->cr_gid;
  374         pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
  375         bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
  376         aiov[0].iov_base = &pcred;
  377         aiov[0].iov_len = sizeof(pcred);
  378         aiov[1].iov_base = pt->pt_arg;
  379         aiov[1].iov_len = pt->pt_size;
  380         auio.uio_iov = aiov;
  381         auio.uio_iovcnt = 2;
  382         auio.uio_rw = UIO_WRITE;
  383         auio.uio_segflg = UIO_SYSSPACE;
  384         auio.uio_procp = p;
  385         auio.uio_offset = 0;
  386         auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
  387 
  388         error = sosend(so, (struct mbuf *) 0, &auio,
  389                         (struct mbuf *) 0, (struct mbuf *) 0, 0);
  390         if (error)
  391                 goto bad;
  392 
  393         len = auio.uio_resid = sizeof(int);
  394         do {
  395                 struct mbuf *m = 0;
  396                 int flags = MSG_WAITALL;
  397                 fdpunlock(p->p_fd);
  398                 error = soreceive(so, (struct mbuf **) 0, &auio,
  399                                         &m, &cm, &flags);
  400                 fdplock(p->p_fd);
  401                 if (error)
  402                         goto bad;
  403 
  404                 /*
  405                  * Grab an error code from the mbuf.
  406                  */
  407                 if (m) {
  408                         m = m_pullup(m, sizeof(int));   /* Needed? */
  409                         if (m) {
  410                                 error = *(mtod(m, int *));
  411                                 m_freem(m);
  412                         } else {
  413                                 error = EINVAL;
  414                         }
  415                 } else {
  416                         if (cm == 0) {
  417                                 error = ECONNRESET;      /* XXX */
  418 #ifdef notdef
  419                                 break;
  420 #endif
  421                         }
  422                 }
  423         } while (cm == 0 && auio.uio_resid == len && !error);
  424 
  425         if (cm == 0)
  426                 goto bad;
  427 
  428         if (auio.uio_resid) {
  429                 error = 0;
  430 #ifdef notdef
  431                 error = EMSGSIZE;
  432                 goto bad;
  433 #endif
  434         }
  435 
  436         /*
  437          * XXX: Break apart the control message, and retrieve the
  438          * received file descriptor.  Note that more than one descriptor
  439          * may have been received, or that the rights chain may have more
  440          * than a single mbuf in it.  What to do?
  441          */
  442         cmsg = mtod(cm, struct cmsghdr *);
  443         newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
  444         if (newfds == 0) {
  445                 error = ECONNREFUSED;
  446                 goto bad;
  447         }
  448         /*
  449          * At this point the rights message consists of a control message
  450          * header, followed by a data region containing a vector of
  451          * integer file descriptors.  The fds were allocated by the action
  452          * of receiving the control message.
  453          */
  454         ip = (int *)(cmsg + 1);
  455         fd = *ip++;
  456         if (newfds > 1) {
  457                 /*
  458                  * Close extra fds.
  459                  */
  460                 int i;
  461                 printf("portal_open: %d extra fds\n", newfds - 1);
  462                 for (i = 1; i < newfds; i++) {
  463                         portal_closefd(p, *ip);
  464                         ip++;
  465                 }
  466         }
  467 
  468         /*
  469          * Check that the mode the file is being opened for is a subset 
  470          * of the mode of the existing descriptor.
  471          */
  472         if ((fp = fd_getfile(p->p_fd, fd)) == NULL) {
  473                 error = EBADF;
  474                 goto bad;
  475         }
  476         if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
  477                 portal_closefd(p, fd);
  478                 error = EACCES;
  479                 goto bad;
  480         }
  481 
  482         /*
  483          * Save the dup fd in the proc structure then return the
  484          * special error code (ENXIO) which causes magic things to
  485          * happen in vn_open.  The whole concept is, well, hmmm.
  486          */
  487         p->p_dupfd = fd;
  488         error = ENXIO;
  489 
  490 bad:;
  491         /*
  492          * And discard the control message.
  493          */
  494         if (cm) { 
  495                 m_freem(cm);
  496         }
  497 
  498         if (so) {
  499                 soshutdown(so, 2);
  500                 soclose(so);
  501         }
  502         return (error);
  503 }
  504 
  505 int
  506 portal_getattr(void *v)
  507 {
  508         struct vop_getattr_args *ap = v;
  509         struct vnode *vp = ap->a_vp;
  510         struct vattr *vap = ap->a_vap;
  511 
  512         bzero(vap, sizeof(*vap));
  513         vattr_null(vap);
  514         vap->va_uid = 0;
  515         vap->va_gid = 0;
  516         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  517         vap->va_size = DEV_BSIZE;
  518         vap->va_blocksize = DEV_BSIZE;
  519         getnanotime(&vap->va_atime);
  520         vap->va_mtime = vap->va_atime;
  521         vap->va_ctime = vap->va_atime;
  522         vap->va_gen = 0;
  523         vap->va_flags = 0;
  524         vap->va_rdev = 0;
  525         /* vap->va_qbytes = 0; */
  526         vap->va_bytes = 0;
  527         /* vap->va_qsize = 0; */
  528         if (vp->v_flag & VROOT) {
  529                 vap->va_type = VDIR;
  530                 vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
  531                                 S_IRGRP|S_IWGRP|S_IXGRP|
  532                                 S_IROTH|S_IWOTH|S_IXOTH;
  533                 vap->va_nlink = 2;
  534                 vap->va_fileid = 2;
  535         } else {
  536                 vap->va_type = VREG;
  537                 vap->va_mode = S_IRUSR|S_IWUSR|
  538                                 S_IRGRP|S_IWGRP|
  539                                 S_IROTH|S_IWOTH;
  540                 vap->va_nlink = 1;
  541                 vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
  542         }
  543         return (0);
  544 }
  545 
  546 int
  547 portal_setattr(void *v)
  548 {
  549         struct vop_setattr_args *ap = v;
  550 
  551         /*
  552          * Can't mess with the root vnode
  553          */
  554         if (ap->a_vp->v_flag & VROOT)
  555                 return (EACCES);
  556 
  557         if (ap->a_vap->va_flags != VNOVAL)
  558                 return (EOPNOTSUPP);
  559 
  560         return (0);
  561 }
  562 
  563 /*
  564  * Fake readdir, just return empty directory.
  565  * It is hard to deal with '.' and '..' so don't bother.
  566  */
  567 /*ARGSUSED*/
  568 int
  569 portal_readdir(void *v)
  570 {
  571         return (0);
  572 }
  573 
  574 /*ARGSUSED*/
  575 int
  576 portal_inactive(void *v)
  577 {
  578         struct vop_inactive_args *ap = v;
  579 
  580         VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
  581         return (0);
  582 }
  583 
  584 int
  585 portal_reclaim(void *v)
  586 {
  587         struct vop_reclaim_args *ap = v;
  588         struct portalnode *pt = VTOPORTAL(ap->a_vp);
  589 
  590         if (pt->pt_arg) {
  591                 free(pt->pt_arg, M_TEMP);
  592                 pt->pt_arg = 0;
  593         }
  594         FREE(ap->a_vp->v_data, M_TEMP);
  595         ap->a_vp->v_data = 0;
  596 
  597         return (0);
  598 }
  599 
  600 /*
  601  * Return POSIX pathconf information applicable to special devices.
  602  */
  603 int
  604 portal_pathconf(void *v)
  605 {
  606         struct vop_pathconf_args *ap = v;
  607 
  608         switch (ap->a_name) {
  609         case _PC_LINK_MAX:
  610                 *ap->a_retval = LINK_MAX;
  611                 return (0);
  612         case _PC_MAX_CANON:
  613                 *ap->a_retval = MAX_CANON;
  614                 return (0);
  615         case _PC_MAX_INPUT:
  616                 *ap->a_retval = MAX_INPUT;
  617                 return (0);
  618         case _PC_PIPE_BUF:
  619                 *ap->a_retval = PIPE_BUF;
  620                 return (0);
  621         case _PC_CHOWN_RESTRICTED:
  622                 *ap->a_retval = 1;
  623                 return (0);
  624         case _PC_VDISABLE:
  625                 *ap->a_retval = _POSIX_VDISABLE;
  626                 return (0);
  627         default:
  628                 return (EINVAL);
  629         }
  630         /* NOTREACHED */
  631 }
  632 
  633 /*
  634  * Print out the contents of a Portal vnode.
  635  */
  636 /* ARGSUSED */
  637 int
  638 portal_print(void *v)
  639 {
  640         printf("tag VT_PORTAL, portal vnode\n");
  641         return (0);
  642 }
  643 
  644 int
  645 portal_link(void *v) 
  646 {
  647         struct vop_link_args *ap = v;
  648  
  649         VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
  650         vput(ap->a_dvp);
  651         return (EROFS);
  652 }
  653 
  654 int
  655 portal_symlink(void *v)
  656 {
  657         struct vop_symlink_args *ap = v;
  658   
  659         VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
  660         vput(ap->a_dvp);
  661         return (EROFS);
  662 }
  663 
  664 int
  665 portal_badop(void *v)
  666 {
  667         panic ("portal: bad op");
  668         return (0);
  669 }
  670 
  671 int
  672 portal_poll(void *v)
  673 {
  674         struct vop_poll_args *ap = v;
  675 
  676         return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
  677 }

/* [<][>][^][v][top][bottom][index][help] */