The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/coda/coda_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: coda_vnops.c,v 1.50.8.4 2010/08/04 11:00:06 bouyer Exp $       */
    2 
    3 /*
    4  *
    5  *             Coda: an Experimental Distributed File System
    6  *                              Release 3.1
    7  *
    8  *           Copyright (c) 1987-1998 Carnegie Mellon University
    9  *                          All Rights Reserved
   10  *
   11  * Permission  to  use, copy, modify and distribute this software and its
   12  * documentation is hereby granted,  provided  that  both  the  copyright
   13  * notice  and  this  permission  notice  appear  in  all  copies  of the
   14  * software, derivative works or  modified  versions,  and  any  portions
   15  * thereof, and that both notices appear in supporting documentation, and
   16  * that credit is given to Carnegie Mellon University  in  all  documents
   17  * and publicity pertaining to direct or indirect use of this code or its
   18  * derivatives.
   19  *
   20  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
   21  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
   22  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
   23  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
   24  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
   25  * ANY DERIVATIVE WORK.
   26  *
   27  * Carnegie  Mellon  encourages  users  of  this  software  to return any
   28  * improvements or extensions that  they  make,  and  to  grant  Carnegie
   29  * Mellon the rights to redistribute these changes without encumbrance.
   30  *
   31  *      @(#) coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:26:46 rvb Exp $
   32  */
   33 
   34 /*
   35  * Mach Operating System
   36  * Copyright (c) 1990 Carnegie-Mellon University
   37  * Copyright (c) 1989 Carnegie-Mellon University
   38  * All rights reserved.  The CMU software License Agreement specifies
   39  * the terms and conditions for use and redistribution.
   40  */
   41 
   42 /*
   43  * This code was written for the Coda file system at Carnegie Mellon
   44  * University.  Contributers include David Steere, James Kistler, and
   45  * M. Satyanarayanan.
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __KERNEL_RCSID(0, "$NetBSD: coda_vnops.c,v 1.50.8.4 2010/08/04 11:00:06 bouyer Exp $");
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/malloc.h>
   54 #include <sys/errno.h>
   55 #include <sys/acct.h>
   56 #include <sys/file.h>
   57 #include <sys/uio.h>
   58 #include <sys/namei.h>
   59 #include <sys/ioctl.h>
   60 #include <sys/mount.h>
   61 #include <sys/proc.h>
   62 #include <sys/select.h>
   63 #include <sys/user.h>
   64 #include <sys/vnode.h>
   65 #include <sys/kauth.h>
   66 
   67 #include <miscfs/genfs/genfs.h>
   68 
   69 #include <coda/coda.h>
   70 #include <coda/cnode.h>
   71 #include <coda/coda_vnops.h>
   72 #include <coda/coda_venus.h>
   73 #include <coda/coda_opstats.h>
   74 #include <coda/coda_subr.h>
   75 #include <coda/coda_namecache.h>
   76 #include <coda/coda_pioctl.h>
   77 
   78 /*
   79  * These flags select various performance enhancements.
   80  */
   81 int coda_attr_cache  = 1;       /* Set to cache attributes in the kernel */
   82 int coda_symlink_cache = 1;     /* Set to cache symbolic link information */
   83 int coda_access_cache = 1;      /* Set to handle some access checks directly */
   84 
   85 /* structure to keep track of vfs calls */
   86 
   87 struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
   88 
   89 #define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++)
   90 #define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++)
   91 #define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++)
   92 #define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++)
   93 
   94 /* What we are delaying for in printf */
   95 int coda_printf_delay = 0;  /* in microseconds */
   96 int coda_vnop_print_entry = 0;
   97 static int coda_lockdebug = 0;
   98 
   99 #define ENTRY if(coda_vnop_print_entry) myprintf(("Entered %s\n",__func__))
  100 
  101 /* Definition of the vnode operation vector */
  102 
  103 const struct vnodeopv_entry_desc coda_vnodeop_entries[] = {
  104     { &vop_default_desc, coda_vop_error },
  105     { &vop_lookup_desc, coda_lookup },          /* lookup */
  106     { &vop_create_desc, coda_create },          /* create */
  107     { &vop_mknod_desc, coda_vop_error },        /* mknod */
  108     { &vop_open_desc, coda_open },              /* open */
  109     { &vop_close_desc, coda_close },            /* close */
  110     { &vop_access_desc, coda_access },          /* access */
  111     { &vop_getattr_desc, coda_getattr },        /* getattr */
  112     { &vop_setattr_desc, coda_setattr },        /* setattr */
  113     { &vop_read_desc, coda_read },              /* read */
  114     { &vop_write_desc, coda_write },            /* write */
  115     { &vop_fcntl_desc, genfs_fcntl },           /* fcntl */
  116     { &vop_ioctl_desc, coda_ioctl },            /* ioctl */
  117     { &vop_mmap_desc, genfs_mmap },             /* mmap */
  118     { &vop_fsync_desc, coda_fsync },            /* fsync */
  119     { &vop_remove_desc, coda_remove },          /* remove */
  120     { &vop_link_desc, coda_link },              /* link */
  121     { &vop_rename_desc, coda_rename },          /* rename */
  122     { &vop_mkdir_desc, coda_mkdir },            /* mkdir */
  123     { &vop_rmdir_desc, coda_rmdir },            /* rmdir */
  124     { &vop_symlink_desc, coda_symlink },        /* symlink */
  125     { &vop_readdir_desc, coda_readdir },        /* readdir */
  126     { &vop_readlink_desc, coda_readlink },      /* readlink */
  127     { &vop_abortop_desc, coda_abortop },        /* abortop */
  128     { &vop_inactive_desc, coda_inactive },      /* inactive */
  129     { &vop_reclaim_desc, coda_reclaim },        /* reclaim */
  130     { &vop_lock_desc, coda_lock },              /* lock */
  131     { &vop_unlock_desc, coda_unlock },          /* unlock */
  132     { &vop_bmap_desc, coda_bmap },              /* bmap */
  133     { &vop_strategy_desc, coda_strategy },      /* strategy */
  134     { &vop_print_desc, coda_vop_error },        /* print */
  135     { &vop_islocked_desc, coda_islocked },      /* islocked */
  136     { &vop_pathconf_desc, coda_vop_error },     /* pathconf */
  137     { &vop_advlock_desc, coda_vop_nop },        /* advlock */
  138     { &vop_bwrite_desc, coda_vop_error },       /* bwrite */
  139     { &vop_lease_desc, coda_vop_nop },          /* lease */
  140     { &vop_seek_desc, genfs_seek },             /* seek */
  141     { &vop_poll_desc, genfs_poll },             /* poll */
  142     { &vop_getpages_desc, coda_getpages },      /* getpages */
  143     { &vop_putpages_desc, coda_putpages },      /* putpages */
  144     { NULL, NULL }
  145 };
  146 
  147 const struct vnodeopv_desc coda_vnodeop_opv_desc =
  148         { &coda_vnodeop_p, coda_vnodeop_entries };
  149 
  150 /* Definitions of NetBSD vnodeop interfaces */
  151 
  152 /*
  153  * A generic error routine.  Return EIO without looking at arguments.
  154  */
  155 int
  156 coda_vop_error(void *anon) {
  157     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
  158 
  159     if (codadebug) {
  160         myprintf(("coda_vop_error: Vnode operation %s called (error).\n",
  161                   (*desc)->vdesc_name));
  162     }
  163 
  164     return EIO;
  165 }
  166 
  167 /* A generic do-nothing.  For lease_check, advlock */
  168 int
  169 coda_vop_nop(void *anon) {
  170     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
  171 
  172     if (codadebug) {
  173         myprintf(("Vnode operation %s called, but unsupported\n",
  174                   (*desc)->vdesc_name));
  175     }
  176    return (0);
  177 }
  178 
  179 int
  180 coda_vnodeopstats_init(void)
  181 {
  182         int i;
  183 
  184         for(i=0;i<CODA_VNODEOPS_SIZE;i++) {
  185                 coda_vnodeopstats[i].opcode = i;
  186                 coda_vnodeopstats[i].entries = 0;
  187                 coda_vnodeopstats[i].sat_intrn = 0;
  188                 coda_vnodeopstats[i].unsat_intrn = 0;
  189                 coda_vnodeopstats[i].gen_intrn = 0;
  190         }
  191 
  192         return 0;
  193 }
  194 
  195 /*
  196  * XXX The entire relationship between VOP_OPEN and having a container
  197  * file (via venus_open) needs to be reexamined.  In particular, it's
  198  * valid to open/mmap/close and then reference.  Instead of doing
  199  * VOP_OPEN when getpages needs a container, we should do the
  200  * venus_open part, and record that the vnode has opened the container
  201  * for getpages, and do the matching logical close on coda_inactive.
  202  * Further, coda_rdwr needs a container file, and sometimes needs to
  203  * do the equivalent of open (core dumps).
  204  */
  205 /*
  206  * coda_open calls Venus to return the device and inode of the
  207  * container file, and then obtains a vnode for that file.  The
  208  * container vnode is stored in the coda vnode, and a reference is
  209  * added for each open file.
  210  */
  211 int
  212 coda_open(void *v)
  213 {
  214     /*
  215      * NetBSD can pass the O_EXCL flag in mode, even though the check
  216      * has already happened.  Venus defensively assumes that if open
  217      * is passed the EXCL, it must be a bug.  We strip the flag here.
  218      */
  219 /* true args */
  220     struct vop_open_args *ap = v;
  221     struct vnode *vp = ap->a_vp;
  222     struct cnode *cp = VTOC(vp);
  223     int flag = ap->a_mode & (~O_EXCL);
  224     kauth_cred_t cred = ap->a_cred;
  225     struct lwp *l = ap->a_l;
  226 /* locals */
  227     int error;
  228     dev_t dev;                  /* container file device, inode, vnode */
  229     ino_t inode;
  230     struct vnode *container_vp;
  231 
  232     MARK_ENTRY(CODA_OPEN_STATS);
  233 
  234     /* Check for open of control file. */
  235     if (IS_CTL_VP(vp)) {
  236         /* if (WRITABLE(flag)) */
  237         if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
  238             MARK_INT_FAIL(CODA_OPEN_STATS);
  239             return(EACCES);
  240         }
  241         MARK_INT_SAT(CODA_OPEN_STATS);
  242         return(0);
  243     }
  244 
  245     error = venus_open(vtomi(vp), &cp->c_fid, flag, cred, l, &dev, &inode);
  246     if (error)
  247         return (error);
  248     if (!error) {
  249         CODADEBUG(CODA_OPEN, myprintf(("open: dev %d inode %llu result %d\n",
  250                                   dev, (unsigned long long)inode, error)); )
  251     }
  252 
  253     /* 
  254      * Obtain locked and referenced container vnode from container
  255      * device/inode.
  256      */
  257     error = coda_grab_vnode(dev, inode, &container_vp);
  258     if (error)
  259         return (error);
  260 
  261     /* Save the vnode pointer for the container file. */
  262     if (cp->c_ovp == NULL) {
  263         cp->c_ovp = container_vp;
  264     } else {
  265         if (cp->c_ovp != container_vp)
  266             /*
  267              * Perhaps venus returned a different container, or
  268              * something else went wrong.
  269              */
  270             panic("coda_open: cp->c_ovp != container_vp");
  271     }
  272     cp->c_ocount++;
  273 
  274     /* Flush the attribute cache if writing the file. */
  275     if (flag & FWRITE) {
  276         cp->c_owrite++;
  277         cp->c_flags &= ~C_VATTR;
  278     }
  279 
  280     /* 
  281      * Save the <device, inode> pair for the container file to speed
  282      * up subsequent reads while closed (mmap, program execution).
  283      * This is perhaps safe because venus will invalidate the node
  284      * before changing the container file mapping.
  285      */
  286     cp->c_device = dev;
  287     cp->c_inode = inode;
  288 
  289     /* Open the container file. */
  290     error = VOP_OPEN(container_vp, flag, cred, l);
  291     /* 
  292      * Drop the lock on the container, after we have done VOP_OPEN
  293      * (which requires a locked vnode).
  294      */
  295     VOP_UNLOCK(container_vp, 0);
  296     return(error);
  297 }
  298 
  299 /*
  300  * Close the cache file used for I/O and notify Venus.
  301  */
  302 int
  303 coda_close(void *v)
  304 {
  305 /* true args */
  306     struct vop_close_args *ap = v;
  307     struct vnode *vp = ap->a_vp;
  308     struct cnode *cp = VTOC(vp);
  309     int flag = ap->a_fflag;
  310     kauth_cred_t cred = ap->a_cred;
  311     struct lwp *l = ap->a_l;
  312 /* locals */
  313     int error;
  314 
  315     MARK_ENTRY(CODA_CLOSE_STATS);
  316 
  317     /* Check for close of control file. */
  318     if (IS_CTL_VP(vp)) {
  319         MARK_INT_SAT(CODA_CLOSE_STATS);
  320         return(0);
  321     }
  322 
  323     /*
  324      * XXX The IS_UNMOUNTING part of this is very suspect.
  325      */ 
  326     if (IS_UNMOUNTING(cp)) {
  327         if (cp->c_ovp) {
  328 #ifdef  CODA_VERBOSE
  329             printf("coda_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n",
  330                     vp->v_usecount, cp->c_ovp, vp, cp);
  331 #endif
  332 #ifdef  hmm
  333             vgone(cp->c_ovp);
  334 #else
  335             vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
  336             VOP_CLOSE(cp->c_ovp, flag, cred, l); /* Do errors matter here? */
  337             vput(cp->c_ovp);
  338 #endif
  339         } else {
  340 #ifdef  CODA_VERBOSE
  341             printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
  342 #endif
  343         }
  344         return ENODEV;
  345     }
  346 
  347     /* Lock the container node, and VOP_CLOSE it. */
  348     vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
  349     VOP_CLOSE(cp->c_ovp, flag, cred, l); /* Do errors matter here? */
  350     /*
  351      * Drop the lock we just obtained, and vrele the container vnode.
  352      * Decrement reference counts, and clear container vnode pointer on
  353      * last close.
  354      */
  355     vput(cp->c_ovp);
  356     if (flag & FWRITE)
  357         --cp->c_owrite;
  358     if (--cp->c_ocount == 0)
  359         cp->c_ovp = NULL;
  360 
  361     error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, l);
  362 
  363     CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); )
  364     return(error);
  365 }
  366 
  367 int
  368 coda_read(void *v)
  369 {
  370     struct vop_read_args *ap = v;
  371 
  372     ENTRY;
  373     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ,
  374                     ap->a_ioflag, ap->a_cred, curlwp));
  375 }
  376 
  377 int
  378 coda_write(void *v)
  379 {
  380     struct vop_write_args *ap = v;
  381 
  382     ENTRY;
  383     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE,
  384                     ap->a_ioflag, ap->a_cred, curlwp));
  385 }
  386 
  387 int
  388 coda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag,
  389         kauth_cred_t cred, struct lwp *l)
  390 {
  391 /* upcall decl */
  392   /* NOTE: container file operation!!! */
  393 /* locals */
  394     struct cnode *cp = VTOC(vp);
  395     struct vnode *cfvp = cp->c_ovp;
  396     struct proc *p = l->l_proc;
  397     int opened_internally = 0;
  398     int error = 0;
  399 
  400     MARK_ENTRY(CODA_RDWR_STATS);
  401 
  402     CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %lu, %lld)\n", rw,
  403                               uiop->uio_iov->iov_base,
  404                               (unsigned long) uiop->uio_resid,
  405                               (long long) uiop->uio_offset)); )
  406 
  407     /* Check for rdwr of control object. */
  408     if (IS_CTL_VP(vp)) {
  409         MARK_INT_FAIL(CODA_RDWR_STATS);
  410         return(EINVAL);
  411     }
  412 
  413     /* Redirect the request to UFS. */
  414 
  415     /*
  416      * If file is not already open this must be a page
  417      * {read,write} request.  Iget the cache file's inode
  418      * pointer if we still have its <device, inode> pair.
  419      * Otherwise, we must do an internal open to derive the
  420      * pair.
  421      * XXX Integrate this into a coherent strategy for container
  422      * file acquisition.
  423      */
  424     if (cfvp == NULL) {
  425         /*
  426          * If we're dumping core, do the internal open. Otherwise
  427          * venus won't have the correct size of the core when
  428          * it's completely written.
  429          */
  430         if (cp->c_inode != 0 && !(p && (p->p_acflag & ACORE))) {
  431             printf("coda_rdwr: grabbing container vnode, losing reference\n");
  432             /* Get locked and refed vnode. */
  433             error = coda_grab_vnode(cp->c_device, cp->c_inode, &cfvp);
  434             if (error) {
  435                 MARK_INT_FAIL(CODA_RDWR_STATS);
  436                 return(error);
  437             }
  438             /* 
  439              * Drop lock. 
  440              * XXX Where is reference released.
  441              */
  442             VOP_UNLOCK(cfvp, 0);
  443         }
  444         else {
  445             printf("coda_rdwr: internal VOP_OPEN\n");
  446             opened_internally = 1;
  447             MARK_INT_GEN(CODA_OPEN_STATS);
  448             error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE),
  449                              cred, l);
  450 #ifdef  CODA_VERBOSE
  451 printf("coda_rdwr: Internally Opening %p\n", vp);
  452 #endif
  453             if (error) {
  454                 MARK_INT_FAIL(CODA_RDWR_STATS);
  455                 return(error);
  456             }
  457             cfvp = cp->c_ovp;
  458         }
  459     }
  460 
  461     /* Have UFS handle the call. */
  462     CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = %s, refcnt = %d\n",
  463                         coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); )
  464 
  465     if (rw == UIO_READ) {
  466         error = VOP_READ(cfvp, uiop, ioflag, cred);
  467     } else {
  468         error = VOP_WRITE(cfvp, uiop, ioflag, cred);
  469     }
  470 
  471     if (error)
  472         MARK_INT_FAIL(CODA_RDWR_STATS);
  473     else
  474         MARK_INT_SAT(CODA_RDWR_STATS);
  475 
  476     /* Do an internal close if necessary. */
  477     if (opened_internally) {
  478         MARK_INT_GEN(CODA_CLOSE_STATS);
  479         (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, l);
  480     }
  481 
  482     /* Invalidate cached attributes if writing. */
  483     if (rw == UIO_WRITE)
  484         cp->c_flags &= ~C_VATTR;
  485     return(error);
  486 }
  487 
  488 int
  489 coda_ioctl(void *v)
  490 {
  491 /* true args */
  492     struct vop_ioctl_args *ap = v;
  493     struct vnode *vp = ap->a_vp;
  494     int com = ap->a_command;
  495     caddr_t data = ap->a_data;
  496     int flag = ap->a_fflag;
  497     kauth_cred_t cred = ap->a_cred;
  498     struct lwp  *l = ap->a_l;
  499 /* locals */
  500     int error;
  501     struct vnode *tvp;
  502     struct nameidata ndp;
  503     struct PioctlData *iap = (struct PioctlData *)data;
  504 
  505     MARK_ENTRY(CODA_IOCTL_STATS);
  506 
  507     CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));)
  508 
  509     /* Don't check for operation on a dying object, for ctlvp it
  510        shouldn't matter */
  511 
  512     /* Must be control object to succeed. */
  513     if (!IS_CTL_VP(vp)) {
  514         MARK_INT_FAIL(CODA_IOCTL_STATS);
  515         CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));)
  516             return (EOPNOTSUPP);
  517     }
  518     /* Look up the pathname. */
  519 
  520     /* Should we use the name cache here? It would get it from
  521        lookupname sooner or later anyway, right? */
  522 
  523     NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE,
  524         iap->path, l);
  525     error = namei(&ndp);
  526     tvp = ndp.ni_vp;
  527 
  528     if (error) {
  529         MARK_INT_FAIL(CODA_IOCTL_STATS);
  530         CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n",
  531                                    error));)
  532         return(error);
  533     }
  534 
  535     /*
  536      * Make sure this is a coda style cnode, but it may be a
  537      * different vfsp
  538      */
  539     /* XXX: this totally violates the comment about vtagtype in vnode.h */
  540     if (tvp->v_tag != VT_CODA) {
  541         vrele(tvp);
  542         MARK_INT_FAIL(CODA_IOCTL_STATS);
  543         CODADEBUG(CODA_IOCTL,
  544                  myprintf(("coda_ioctl error: %s not a coda object\n",
  545                         iap->path));)
  546         return(EINVAL);
  547     }
  548 
  549     if (iap->vi.in_size > VC_MAXDATASIZE || iap->vi.out_size > VC_MAXDATASIZE) {
  550         vrele(tvp);
  551         return(EINVAL);
  552     }
  553     error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, l);
  554 
  555     if (error)
  556         MARK_INT_FAIL(CODA_IOCTL_STATS);
  557     else
  558         CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); )
  559 
  560     vrele(tvp);
  561     return(error);
  562 }
  563 
  564 /*
  565  * To reduce the cost of a user-level venus;we cache attributes in
  566  * the kernel.  Each cnode has storage allocated for an attribute. If
  567  * c_vattr is valid, return a reference to it. Otherwise, get the
  568  * attributes from venus and store them in the cnode.  There is some
  569  * question if this method is a security leak. But I think that in
  570  * order to make this call, the user must have done a lookup and
  571  * opened the file, and therefore should already have access.
  572  */
  573 int
  574 coda_getattr(void *v)
  575 {
  576 /* true args */
  577     struct vop_getattr_args *ap = v;
  578     struct vnode *vp = ap->a_vp;
  579     struct cnode *cp = VTOC(vp);
  580     struct vattr *vap = ap->a_vap;
  581     kauth_cred_t cred = ap->a_cred;
  582     struct lwp *l = ap->a_l;
  583 /* locals */
  584     int error;
  585 
  586     MARK_ENTRY(CODA_GETATTR_STATS);
  587 
  588     /* Check for getattr of control object. */
  589     if (IS_CTL_VP(vp)) {
  590         MARK_INT_FAIL(CODA_GETATTR_STATS);
  591         return(ENOENT);
  592     }
  593 
  594     /* Check to see if the attributes have already been cached */
  595     if (VALID_VATTR(cp)) {
  596         CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: %s\n",
  597                                         coda_f2s(&cp->c_fid)));});
  598         CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
  599                  print_vattr(&cp->c_vattr); );
  600 
  601         *vap = cp->c_vattr;
  602         MARK_INT_SAT(CODA_GETATTR_STATS);
  603         return(0);
  604     }
  605 
  606     error = venus_getattr(vtomi(vp), &cp->c_fid, cred, l, vap);
  607 
  608     if (!error) {
  609         CODADEBUG(CODA_GETATTR, myprintf(("getattr miss %s: result %d\n",
  610                                      coda_f2s(&cp->c_fid), error)); )
  611 
  612         CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
  613                  print_vattr(vap);      );
  614 
  615         /* If not open for write, store attributes in cnode */
  616         if ((cp->c_owrite == 0) && (coda_attr_cache)) {
  617             cp->c_vattr = *vap;
  618             cp->c_flags |= C_VATTR;
  619         }
  620 
  621     }
  622     return(error);
  623 }
  624 
  625 int
  626 coda_setattr(void *v)
  627 {
  628 /* true args */
  629     struct vop_setattr_args *ap = v;
  630     struct vnode *vp = ap->a_vp;
  631     struct cnode *cp = VTOC(vp);
  632     struct vattr *vap = ap->a_vap;
  633     kauth_cred_t cred = ap->a_cred;
  634     struct lwp *l = ap->a_l;
  635 /* locals */
  636     int error;
  637 
  638     MARK_ENTRY(CODA_SETATTR_STATS);
  639 
  640     /* Check for setattr of control object. */
  641     if (IS_CTL_VP(vp)) {
  642         MARK_INT_FAIL(CODA_SETATTR_STATS);
  643         return(ENOENT);
  644     }
  645 
  646     if (codadebug & CODADBGMSK(CODA_SETATTR)) {
  647         print_vattr(vap);
  648     }
  649     error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, l);
  650 
  651     if (!error)
  652         cp->c_flags &= ~C_VATTR;
  653 
  654     CODADEBUG(CODA_SETATTR,     myprintf(("setattr %d\n", error)); )
  655     return(error);
  656 }
  657 
  658 int
  659 coda_access(void *v)
  660 {
  661 /* true args */
  662     struct vop_access_args *ap = v;
  663     struct vnode *vp = ap->a_vp;
  664     struct cnode *cp = VTOC(vp);
  665     int mode = ap->a_mode;
  666     kauth_cred_t cred = ap->a_cred;
  667     struct lwp *l = ap->a_l;
  668 /* locals */
  669     int error;
  670 
  671     MARK_ENTRY(CODA_ACCESS_STATS);
  672 
  673     /* Check for access of control object.  Only read access is
  674        allowed on it. */
  675     if (IS_CTL_VP(vp)) {
  676         /* bogus hack - all will be marked as successes */
  677         MARK_INT_SAT(CODA_ACCESS_STATS);
  678         return(((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
  679                ? 0 : EACCES);
  680     }
  681 
  682     /*
  683      * if the file is a directory, and we are checking exec (eg lookup)
  684      * access, and the file is in the namecache, then the user must have
  685      * lookup access to it.
  686      */
  687     if (coda_access_cache) {
  688         if ((vp->v_type == VDIR) && (mode & VEXEC)) {
  689             if (coda_nc_lookup(cp, ".", 1, cred)) {
  690                 MARK_INT_SAT(CODA_ACCESS_STATS);
  691                 return(0);                     /* it was in the cache */
  692             }
  693         }
  694     }
  695 
  696     error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, l);
  697 
  698     return(error);
  699 }
  700 
  701 /*
  702  * CODA abort op, called after namei() when a CREATE/DELETE isn't actually
  703  * done. If a buffer has been saved in anticipation of a coda_create or
  704  * a coda_remove, delete it.
  705  */
  706 /* ARGSUSED */
  707 int
  708 coda_abortop(void *v)
  709 {
  710 /* true args */
  711     struct vop_abortop_args /* {
  712         struct vnode *a_dvp;
  713         struct componentname *a_cnp;
  714     } */ *ap = v;
  715 /* upcall decl */
  716 /* locals */
  717 
  718     if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
  719         PNBUF_PUT(ap->a_cnp->cn_pnbuf);
  720     return (0);
  721 }
  722 
  723 int
  724 coda_readlink(void *v)
  725 {
  726 /* true args */
  727     struct vop_readlink_args *ap = v;
  728     struct vnode *vp = ap->a_vp;
  729     struct cnode *cp = VTOC(vp);
  730     struct uio *uiop = ap->a_uio;
  731     kauth_cred_t cred = ap->a_cred;
  732 /* locals */
  733     struct lwp *l = curlwp;
  734     int error;
  735     char *str;
  736     int len;
  737 
  738     MARK_ENTRY(CODA_READLINK_STATS);
  739 
  740     /* Check for readlink of control object. */
  741     if (IS_CTL_VP(vp)) {
  742         MARK_INT_FAIL(CODA_READLINK_STATS);
  743         return(ENOENT);
  744     }
  745 
  746     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */
  747         uiop->uio_rw = UIO_READ;
  748         error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
  749         if (error)
  750             MARK_INT_FAIL(CODA_READLINK_STATS);
  751         else
  752             MARK_INT_SAT(CODA_READLINK_STATS);
  753         return(error);
  754     }
  755 
  756     error = venus_readlink(vtomi(vp), &cp->c_fid, cred, l, &str, &len);
  757 
  758     if (!error) {
  759         uiop->uio_rw = UIO_READ;
  760         error = uiomove(str, len, uiop);
  761 
  762         if (coda_symlink_cache) {
  763             cp->c_symlink = str;
  764             cp->c_symlen = len;
  765             cp->c_flags |= C_SYMLINK;
  766         } else
  767             CODA_FREE(str, len);
  768     }
  769 
  770     CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));)
  771     return(error);
  772 }
  773 
  774 int
  775 coda_fsync(void *v)
  776 {
  777 /* true args */
  778     struct vop_fsync_args *ap = v;
  779     struct vnode *vp = ap->a_vp;
  780     struct cnode *cp = VTOC(vp);
  781     kauth_cred_t cred = ap->a_cred;
  782     struct lwp *l = ap->a_l;
  783 /* locals */
  784     struct vnode *convp = cp->c_ovp;
  785     int error;
  786 
  787     MARK_ENTRY(CODA_FSYNC_STATS);
  788 
  789     /* Check for fsync on an unmounting object */
  790     /* The NetBSD kernel, in it's infinite wisdom, can try to fsync
  791      * after an unmount has been initiated.  This is a Bad Thing,
  792      * which we have to avoid.  Not a legitimate failure for stats.
  793      */
  794     if (IS_UNMOUNTING(cp)) {
  795         return(ENODEV);
  796     }
  797 
  798     /* Check for fsync of control object. */
  799     if (IS_CTL_VP(vp)) {
  800         MARK_INT_SAT(CODA_FSYNC_STATS);
  801         return(0);
  802     }
  803 
  804     if (convp)
  805         VOP_FSYNC(convp, cred, MNT_WAIT, 0, 0, l);
  806 
  807     /*
  808      * We can expect fsync on any vnode at all if venus is pruging it.
  809      * Venus can't very well answer the fsync request, now can it?
  810      * Hopefully, it won't have to, because hopefully, venus preserves
  811      * the (possibly untrue) invariant that it never purges an open
  812      * vnode.  Hopefully.
  813      */
  814     if (cp->c_flags & C_PURGING) {
  815         return(0);
  816     }
  817 
  818     error = venus_fsync(vtomi(vp), &cp->c_fid, cred, l);
  819 
  820     CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); );
  821     return(error);
  822 }
  823 
  824 /*
  825  * vp is locked on entry, and we must unlock it.
  826  * XXX This routine is suspect and probably needs rewriting.
  827  */
  828 int
  829 coda_inactive(void *v)
  830 {
  831 /* true args */
  832     struct vop_inactive_args *ap = v;
  833     struct vnode *vp = ap->a_vp;
  834     struct cnode *cp = VTOC(vp);
  835     kauth_cred_t cred __attribute__((unused)) = NULL;
  836     struct lwp *l __attribute__((unused)) = ap->a_l;
  837 
  838     /* We don't need to send inactive to venus - DCS */
  839     MARK_ENTRY(CODA_INACTIVE_STATS);
  840 
  841     if (IS_CTL_VP(vp)) {
  842         MARK_INT_SAT(CODA_INACTIVE_STATS);
  843         return 0;
  844     }
  845 
  846     CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n",
  847                                   coda_f2s(&cp->c_fid), vp->v_mount));)
  848 
  849     /* If an array has been allocated to hold the symlink, deallocate it */
  850     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
  851         if (cp->c_symlink == NULL)
  852             panic("coda_inactive: null symlink pointer in cnode");
  853 
  854         CODA_FREE(cp->c_symlink, cp->c_symlen);
  855         cp->c_flags &= ~C_SYMLINK;
  856         cp->c_symlen = 0;
  857     }
  858 
  859     /* Remove it from the table so it can't be found. */
  860     coda_unsave(cp);
  861     if (vp->v_mount->mnt_data == NULL) {
  862         myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp));
  863         panic("badness in coda_inactive");
  864     }
  865 
  866     if (IS_UNMOUNTING(cp)) {
  867         /* XXX Do we need to VOP_CLOSE container vnodes? */
  868         if (vp->v_usecount > 0)
  869             printf("coda_inactive: IS_UNMOUNTING %p usecount %d\n",
  870                    vp, vp->v_usecount);
  871         if (cp->c_ovp != NULL)
  872             printf("coda_inactive: %p ovp != NULL\n", vp);
  873         VOP_UNLOCK(vp, 0);
  874     } else {
  875         /* Sanity checks that perhaps should be panic. */
  876         if (vp->v_usecount) {
  877             printf("coda_inactive: %p usecount %d\n", vp, vp->v_usecount);
  878         }
  879         if (cp->c_ovp != NULL) {
  880             printf("coda_inactive: %p ovp != NULL\n", vp);
  881         }
  882         VOP_UNLOCK(vp, 0);
  883         vgone(vp);
  884     }
  885 
  886     MARK_INT_SAT(CODA_INACTIVE_STATS);
  887     return(0);
  888 }
  889 
  890 /*
  891  * Coda does not use the normal namecache, but a private version.
  892  * Consider how to use the standard facility instead.
  893  */
  894 int
  895 coda_lookup(void *v)
  896 {
  897 /* true args */
  898     struct vop_lookup_args *ap = v;
  899     /* (locked) vnode of dir in which to do lookup */
  900     struct vnode *dvp = ap->a_dvp;
  901     struct cnode *dcp = VTOC(dvp);
  902     /* output variable for result */
  903     struct vnode **vpp = ap->a_vpp;
  904     /* name to lookup */
  905     struct componentname *cnp = ap->a_cnp;
  906     kauth_cred_t cred = cnp->cn_cred;
  907     struct lwp *l = cnp->cn_lwp;
  908 /* locals */
  909     struct cnode *cp;
  910     const char *nm = cnp->cn_nameptr;
  911     int len = cnp->cn_namelen;
  912     int flags = cnp->cn_flags;
  913     int isdot;
  914     CodaFid VFid;
  915     int vtype;
  916     int error = 0;
  917 
  918     MARK_ENTRY(CODA_LOOKUP_STATS);
  919 
  920     CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n",
  921                                    nm, coda_f2s(&dcp->c_fid))););
  922 
  923     /*
  924      * XXX componentname flags in MODMASK are not handled at all
  925      */
  926 
  927     /*
  928      * The overall strategy is to switch on the lookup type and get a
  929      * result vnode that is vref'd but not locked.  Then, the code at
  930      * exit: switches on ., .., and regular lookups and does the right
  931      * locking.
  932      */
  933 
  934     /* Check for lookup of control object. */
  935     if (IS_CTL_NAME(dvp, nm, len)) {
  936         *vpp = coda_ctlvp;
  937         vref(*vpp);
  938         MARK_INT_SAT(CODA_LOOKUP_STATS);
  939         goto exit;
  940     }
  941 
  942     /* Avoid trying to hand venus an unreasonably long name. */
  943     if (len+1 > CODA_MAXNAMLEN) {
  944         MARK_INT_FAIL(CODA_LOOKUP_STATS);
  945         CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %s (%s)\n",
  946                                     coda_f2s(&dcp->c_fid), nm)););
  947         *vpp = (struct vnode *)0;
  948         error = EINVAL;
  949         goto exit;
  950     }
  951 
  952     /*
  953      * XXX Check for DOT lookups, and short circuit all the caches,
  954      * just doing an extra vref.  (venus guarantees that lookup of
  955      * . returns self.)
  956      */
  957     isdot = (len == 1 && nm[0] == '.');
  958 
  959     /*
  960      * Try to resolve the lookup in the minicache.  If that fails, ask
  961      * venus to do the lookup.  XXX The interaction between vnode
  962      * locking and any locking that coda does is not clear.
  963      */
  964     cp = coda_nc_lookup(dcp, nm, len, cred);
  965     if (cp) {
  966         *vpp = CTOV(cp);
  967         vref(*vpp);
  968         CODADEBUG(CODA_LOOKUP,
  969                  myprintf(("lookup result %d vpp %p\n",error,*vpp));)
  970     } else {
  971         /* The name wasn't cached, so ask Venus. */
  972         error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, l, &VFid, &vtype);
  973 
  974         if (error) {
  975             MARK_INT_FAIL(CODA_LOOKUP_STATS);
  976             CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %s (%s)%d\n",
  977                                         coda_f2s(&dcp->c_fid), nm, error));)
  978             *vpp = (struct vnode *)0;
  979         } else {
  980             MARK_INT_SAT(CODA_LOOKUP_STATS);
  981             CODADEBUG(CODA_LOOKUP,
  982                      myprintf(("lookup: %s type %o result %d\n",
  983                             coda_f2s(&VFid), vtype, error)); )
  984 
  985             cp = make_coda_node(&VFid, dvp->v_mount, vtype);
  986             *vpp = CTOV(cp);
  987             /* vpp is now vrefed. */
  988 
  989             /*
  990              * Unless this vnode is marked CODA_NOCACHE, enter it into
  991              * the coda name cache to avoid a future venus round-trip.
  992              * XXX Interaction with componentname NOCACHE is unclear.
  993              */
  994             if (!(vtype & CODA_NOCACHE))
  995                 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
  996         }
  997     }
  998 
  999  exit:
 1000     /*
 1001      * If we are creating, and this was the last name to be looked up,
 1002      * and the error was ENOENT, then make the leaf NULL and return
 1003      * success.
 1004      * XXX Check against new lookup rules.
 1005      */
 1006     if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
 1007         && (cnp->cn_flags & ISLASTCN)
 1008         && (error == ENOENT))
 1009     {
 1010         error = EJUSTRETURN;
 1011         cnp->cn_flags |= SAVENAME;
 1012         *ap->a_vpp = NULL;
 1013     }
 1014 
 1015     /*
 1016      * If we are removing, and we are at the last element, and we
 1017      * found it, then we need to keep the name around so that the
 1018      * removal will go ahead as planned.
 1019      * XXX Check against new lookup rules.
 1020      */
 1021     if ((cnp->cn_nameiop == DELETE)
 1022         && (cnp->cn_flags & ISLASTCN)
 1023         && !error)
 1024     {
 1025         cnp->cn_flags |= SAVENAME;
 1026     }
 1027 
 1028     /*
 1029      * If the lookup succeeded, we must generally lock the returned
 1030      * vnode.  This could be a ., .., or normal lookup.  See
 1031      * vnodeops(9) for the details.
 1032      */
 1033     /*
 1034      * XXX LK_RETRY is likely incorrect.  Handle vn_lock failure
 1035      * somehow, and remove LK_RETRY.
 1036      */
 1037     if (!error || (error == EJUSTRETURN)) {
 1038         /* Lookup has a value and it isn't "."? */
 1039         if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
 1040             if (flags & ISDOTDOT)
 1041                 /* ..: unlock parent */
 1042                 VOP_UNLOCK(dvp, 0);
 1043             /* all but .: lock child */
 1044             vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY);
 1045             if (flags & ISDOTDOT)
 1046                 /* ..: relock parent */
 1047                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
 1048         }
 1049         /* else .: leave dvp locked */
 1050     } else {
 1051         /* The lookup failed, so return NULL.  Leave dvp locked. */
 1052         *ap->a_vpp = NULL;
 1053     }
 1054     return(error);
 1055 }
 1056 
 1057 /*ARGSUSED*/
 1058 int
 1059 coda_create(void *v)
 1060 {
 1061 /* true args */
 1062     struct vop_create_args *ap = v;
 1063     struct vnode *dvp = ap->a_dvp;
 1064     struct cnode *dcp = VTOC(dvp);
 1065     struct vattr *va = ap->a_vap;
 1066     int exclusive = 1;
 1067     int mode = ap->a_vap->va_mode;
 1068     struct vnode **vpp = ap->a_vpp;
 1069     struct componentname  *cnp = ap->a_cnp;
 1070     kauth_cred_t cred = cnp->cn_cred;
 1071     struct lwp *l = cnp->cn_lwp;
 1072 /* locals */
 1073     int error;
 1074     struct cnode *cp;
 1075     const char *nm = cnp->cn_nameptr;
 1076     int len = cnp->cn_namelen;
 1077     CodaFid VFid;
 1078     struct vattr attr;
 1079 
 1080     MARK_ENTRY(CODA_CREATE_STATS);
 1081 
 1082     /* All creates are exclusive XXX */
 1083     /* I'm assuming the 'mode' argument is the file mode bits XXX */
 1084 
 1085     /* Check for create of control object. */
 1086     if (IS_CTL_NAME(dvp, nm, len)) {
 1087         *vpp = (struct vnode *)0;
 1088         MARK_INT_FAIL(CODA_CREATE_STATS);
 1089         return(EACCES);
 1090     }
 1091 
 1092     error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, l, &VFid, &attr);
 1093 
 1094     if (!error) {
 1095 
 1096         /*
 1097          * XXX Violation of venus/kernel invariants is a difficult case,
 1098          * but venus should not be able to cause a panic.
 1099          */
 1100         /* If this is an exclusive create, panic if the file already exists. */
 1101         /* Venus should have detected the file and reported EEXIST. */
 1102 
 1103         if ((exclusive == 1) &&
 1104             (coda_find(&VFid) != NULL))
 1105             panic("cnode existed for newly created file!");
 1106 
 1107         cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
 1108         *vpp = CTOV(cp);
 1109 
 1110         /* XXX vnodeops doesn't say this argument can be changed. */
 1111         /* Update va to reflect the new attributes. */
 1112         (*va) = attr;
 1113 
 1114         /* Update the attribute cache and mark it as valid */
 1115         if (coda_attr_cache) {
 1116             VTOC(*vpp)->c_vattr = attr;
 1117             VTOC(*vpp)->c_flags |= C_VATTR;
 1118         }
 1119 
 1120         /* Invalidate parent's attr cache (modification time has changed). */
 1121         VTOC(dvp)->c_flags &= ~C_VATTR;
 1122 
 1123         /* enter the new vnode in the Name Cache */
 1124         coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
 1125 
 1126         CODADEBUG(CODA_CREATE,
 1127                  myprintf(("create: %s, result %d\n",
 1128                         coda_f2s(&VFid), error)); )
 1129     } else {
 1130         *vpp = (struct vnode *)0;
 1131         CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));)
 1132     }
 1133 
 1134     /*
 1135      * vnodeops(9) says that we must unlock the parent and lock the child.
 1136      * XXX Should we lock the child first?
 1137      */
 1138     vput(dvp);
 1139     if (!error) {
 1140         if ((cnp->cn_flags & LOCKLEAF) == 0) {
 1141             /* This should not happen; flags are for lookup only. */
 1142             printf("coda_create: LOCKLEAF not set!\n");
 1143         }
 1144 
 1145         if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
 1146             /* XXX Perhaps avoid this panic. */
 1147             panic("coda_create: couldn't lock child");
 1148         }
 1149     }
 1150 
 1151     /* Per vnodeops(9), free name except on success and SAVESTART. */
 1152     if (error || (cnp->cn_flags & SAVESTART) == 0) {
 1153         PNBUF_PUT(cnp->cn_pnbuf);
 1154     }
 1155     return(error);
 1156 }
 1157 
 1158 int
 1159 coda_remove(void *v)
 1160 {
 1161 /* true args */
 1162     struct vop_remove_args *ap = v;
 1163     struct vnode *dvp = ap->a_dvp;
 1164     struct cnode *cp = VTOC(dvp);
 1165     struct vnode *vp = ap->a_vp;
 1166     struct componentname  *cnp = ap->a_cnp;
 1167     kauth_cred_t cred = cnp->cn_cred;
 1168     struct lwp *l = cnp->cn_lwp;
 1169 /* locals */
 1170     int error;
 1171     const char *nm = cnp->cn_nameptr;
 1172     int len = cnp->cn_namelen;
 1173     struct cnode *tp;
 1174 
 1175     MARK_ENTRY(CODA_REMOVE_STATS);
 1176 
 1177     CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n",
 1178                                    nm, coda_f2s(&cp->c_fid))););
 1179 
 1180     /* Remove the file's entry from the CODA Name Cache */
 1181     /* We're being conservative here, it might be that this person
 1182      * doesn't really have sufficient access to delete the file
 1183      * but we feel zapping the entry won't really hurt anyone -- dcs
 1184      */
 1185     /* I'm gonna go out on a limb here. If a file and a hardlink to it
 1186      * exist, and one is removed, the link count on the other will be
 1187      * off by 1. We could either invalidate the attrs if cached, or
 1188      * fix them. I'll try to fix them. DCS 11/8/94
 1189      */
 1190     tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
 1191     if (tp) {
 1192         if (VALID_VATTR(tp)) {  /* If attrs are cached */
 1193             if (tp->c_vattr.va_nlink > 1) {     /* If it's a hard link */
 1194                 tp->c_vattr.va_nlink--;
 1195             }
 1196         }
 1197 
 1198         coda_nc_zapfile(VTOC(dvp), nm, len);
 1199         /* No need to flush it if it doesn't exist! */
 1200     }
 1201     /* Invalidate the parent's attr cache, the modification time has changed */
 1202     VTOC(dvp)->c_flags &= ~C_VATTR;
 1203 
 1204     /* Check for remove of control object. */
 1205     if (IS_CTL_NAME(dvp, nm, len)) {
 1206         MARK_INT_FAIL(CODA_REMOVE_STATS);
 1207         return(ENOENT);
 1208     }
 1209 
 1210     error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, l);
 1211 
 1212     CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); )
 1213 
 1214     /*
 1215      * Unlock parent and child (avoiding double if ".").
 1216      */
 1217     if (dvp == vp) {
 1218         vrele(vp);
 1219     } else {
 1220         vput(vp);
 1221     }
 1222     vput(dvp);
 1223 
 1224     return(error);
 1225 }
 1226 
 1227 /*
 1228  * dvp is the directory where the link is to go, and is locked.
 1229  * vp is the object to be linked to, and is unlocked.
 1230  * At exit, we must unlock dvp, and vput dvp.
 1231  */
 1232 int
 1233 coda_link(void *v)
 1234 {
 1235 /* true args */
 1236     struct vop_link_args *ap = v;
 1237     struct vnode *vp = ap->a_vp;
 1238     struct cnode *cp = VTOC(vp);
 1239     struct vnode *dvp = ap->a_dvp;
 1240     struct cnode *dcp = VTOC(dvp);
 1241     struct componentname *cnp = ap->a_cnp;
 1242     kauth_cred_t cred = cnp->cn_cred;
 1243     struct lwp *l = cnp->cn_lwp;
 1244 /* locals */
 1245     int error;
 1246     const char *nm = cnp->cn_nameptr;
 1247     int len = cnp->cn_namelen;
 1248 
 1249     MARK_ENTRY(CODA_LINK_STATS);
 1250 
 1251     if (codadebug & CODADBGMSK(CODA_LINK)) {
 1252 
 1253         myprintf(("nb_link:   vp fid: %s\n",
 1254                   coda_f2s(&cp->c_fid)));
 1255         myprintf(("nb_link: dvp fid: %s)\n",
 1256                   coda_f2s(&dcp->c_fid)));
 1257 
 1258     }
 1259     if (codadebug & CODADBGMSK(CODA_LINK)) {
 1260         myprintf(("link:   vp fid: %s\n",
 1261                   coda_f2s(&cp->c_fid)));
 1262         myprintf(("link: dvp fid: %s\n",
 1263                   coda_f2s(&dcp->c_fid)));
 1264 
 1265     }
 1266 
 1267     /* Check for link to/from control object. */
 1268     if (IS_CTL_NAME(dvp, nm, len) || IS_CTL_VP(vp)) {
 1269         MARK_INT_FAIL(CODA_LINK_STATS);
 1270         return(EACCES);
 1271     }
 1272 
 1273     /* If linking . to a name, error out earlier. */
 1274     if (vp == dvp) {
 1275         printf("coda_link vp==dvp\n");
 1276         error = EISDIR;
 1277         goto exit;
 1278     }
 1279 
 1280     /* XXX Why does venus_link need the vnode to be locked?*/
 1281     if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) {
 1282         printf("coda_link: couldn't lock vnode %p\n", vp);
 1283         error = EFAULT;         /* XXX better value */
 1284         goto exit;
 1285     }
 1286     error = venus_link(vtomi(vp), &cp->c_fid, &dcp->c_fid, nm, len, cred, l);
 1287     VOP_UNLOCK(vp, 0);
 1288 
 1289     /* Invalidate parent's attr cache (the modification time has changed). */
 1290     VTOC(dvp)->c_flags &= ~C_VATTR;
 1291     /* Invalidate child's attr cache (XXX why). */
 1292     VTOC(vp)->c_flags &= ~C_VATTR;
 1293 
 1294     CODADEBUG(CODA_LINK,        myprintf(("in link result %d\n",error)); )
 1295 
 1296 exit:
 1297     vput(dvp);
 1298     return(error);
 1299 }
 1300 
 1301 int
 1302 coda_rename(void *v)
 1303 {
 1304 /* true args */
 1305     struct vop_rename_args *ap = v;
 1306     struct vnode *odvp = ap->a_fdvp;
 1307     struct cnode *odcp = VTOC(odvp);
 1308     struct componentname  *fcnp = ap->a_fcnp;
 1309     struct vnode *ndvp = ap->a_tdvp;
 1310     struct cnode *ndcp = VTOC(ndvp);
 1311     struct componentname  *tcnp = ap->a_tcnp;
 1312     kauth_cred_t cred = fcnp->cn_cred;
 1313     struct lwp *l = fcnp->cn_lwp;
 1314 /* true args */
 1315     int error;
 1316     const char *fnm = fcnp->cn_nameptr;
 1317     int flen = fcnp->cn_namelen;
 1318     const char *tnm = tcnp->cn_nameptr;
 1319     int tlen = tcnp->cn_namelen;
 1320 
 1321     MARK_ENTRY(CODA_RENAME_STATS);
 1322 
 1323     /* Hmmm.  The vnodes are already looked up.  Perhaps they are locked?
 1324        This could be Bad. XXX */
 1325 #ifdef OLD_DIAGNOSTIC
 1326     if ((fcnp->cn_cred != tcnp->cn_cred)
 1327         || (fcnp->cn_lwp != tcnp->cn_lwp))
 1328     {
 1329         panic("coda_rename: component names don't agree");
 1330     }
 1331 #endif
 1332 
 1333     /* Check for rename involving control object. */
 1334     if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
 1335         MARK_INT_FAIL(CODA_RENAME_STATS);
 1336         return(EACCES);
 1337     }
 1338 
 1339     /* Problem with moving directories -- need to flush entry for .. */
 1340     if (odvp != ndvp) {
 1341         struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred);
 1342         if (ovcp) {
 1343             struct vnode *ovp = CTOV(ovcp);
 1344             if ((ovp) &&
 1345                 (ovp->v_type == VDIR)) /* If it's a directory */
 1346                 coda_nc_zapfile(VTOC(ovp),"..", 2);
 1347         }
 1348     }
 1349 
 1350     /* Remove the entries for both source and target files */
 1351     coda_nc_zapfile(VTOC(odvp), fnm, flen);
 1352     coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
 1353 
 1354     /* Invalidate the parent's attr cache, the modification time has changed */
 1355     VTOC(odvp)->c_flags &= ~C_VATTR;
 1356     VTOC(ndvp)->c_flags &= ~C_VATTR;
 1357 
 1358     if (flen+1 > CODA_MAXNAMLEN) {
 1359         MARK_INT_FAIL(CODA_RENAME_STATS);
 1360         error = EINVAL;
 1361         goto exit;
 1362     }
 1363 
 1364     if (tlen+1 > CODA_MAXNAMLEN) {
 1365         MARK_INT_FAIL(CODA_RENAME_STATS);
 1366         error = EINVAL;
 1367         goto exit;
 1368     }
 1369 
 1370     error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, l);
 1371 
 1372  exit:
 1373     CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));)
 1374     /* XXX - do we need to call cache pureg on the moved vnode? */
 1375     cache_purge(ap->a_fvp);
 1376 
 1377     /* It seems to be incumbent on us to drop locks on all four vnodes */
 1378     /* From-vnodes are not locked, only ref'd.  To-vnodes are locked. */
 1379 
 1380     vrele(ap->a_fvp);
 1381     vrele(odvp);
 1382 
 1383     if (ap->a_tvp) {
 1384         if (ap->a_tvp == ndvp) {
 1385             vrele(ap->a_tvp);
 1386         } else {
 1387             vput(ap->a_tvp);
 1388         }
 1389     }
 1390 
 1391     vput(ndvp);
 1392     return(error);
 1393 }
 1394 
 1395 int
 1396 coda_mkdir(void *v)
 1397 {
 1398 /* true args */
 1399     struct vop_mkdir_args *ap = v;
 1400     struct vnode *dvp = ap->a_dvp;
 1401     struct cnode *dcp = VTOC(dvp);
 1402     struct componentname  *cnp = ap->a_cnp;
 1403     struct vattr *va = ap->a_vap;
 1404     struct vnode **vpp = ap->a_vpp;
 1405     kauth_cred_t cred = cnp->cn_cred;
 1406     struct lwp *l = cnp->cn_lwp;
 1407 /* locals */
 1408     int error;
 1409     const char *nm = cnp->cn_nameptr;
 1410     int len = cnp->cn_namelen;
 1411     struct cnode *cp;
 1412     CodaFid VFid;
 1413     struct vattr ova;
 1414 
 1415     MARK_ENTRY(CODA_MKDIR_STATS);
 1416 
 1417     /* Check for mkdir of target object. */
 1418     if (IS_CTL_NAME(dvp, nm, len)) {
 1419         *vpp = (struct vnode *)0;
 1420         MARK_INT_FAIL(CODA_MKDIR_STATS);
 1421         return(EACCES);
 1422     }
 1423 
 1424     if (len+1 > CODA_MAXNAMLEN) {
 1425         *vpp = (struct vnode *)0;
 1426         MARK_INT_FAIL(CODA_MKDIR_STATS);
 1427         return(EACCES);
 1428     }
 1429 
 1430     error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, l, &VFid, &ova);
 1431 
 1432     if (!error) {
 1433         if (coda_find(&VFid) != NULL)
 1434             panic("cnode existed for newly created directory!");
 1435 
 1436 
 1437         cp =  make_coda_node(&VFid, dvp->v_mount, va->va_type);
 1438         *vpp = CTOV(cp);
 1439 
 1440         /* enter the new vnode in the Name Cache */
 1441         coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
 1442 
 1443         /* as a side effect, enter "." and ".." for the directory */
 1444         coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
 1445         coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
 1446 
 1447         if (coda_attr_cache) {
 1448             VTOC(*vpp)->c_vattr = ova;          /* update the attr cache */
 1449             VTOC(*vpp)->c_flags |= C_VATTR;     /* Valid attributes in cnode */
 1450         }
 1451 
 1452         /* Invalidate the parent's attr cache, the modification time has changed */
 1453         VTOC(dvp)->c_flags &= ~C_VATTR;
 1454 
 1455         CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n",
 1456                                     coda_f2s(&VFid), error)); )
 1457     } else {
 1458         *vpp = (struct vnode *)0;
 1459         CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));)
 1460     }
 1461 
 1462     /*
 1463      * Currently, all mkdirs explicitly vput their dvp's.
 1464      * It also appears that we *must* lock the vpp, since
 1465      * lockleaf isn't set, but someone down the road is going
 1466      * to try to unlock the new directory.
 1467      */
 1468     vput(dvp);
 1469     if (!error) {
 1470         if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
 1471             panic("coda_mkdir: couldn't lock child");
 1472         }
 1473     }
 1474 
 1475     /* Per vnodeops(9), free name except on success and SAVESTART. */
 1476     if (error || (cnp->cn_flags & SAVESTART) == 0) {
 1477         PNBUF_PUT(cnp->cn_pnbuf);
 1478     }
 1479     return(error);
 1480 }
 1481 
 1482 int
 1483 coda_rmdir(void *v)
 1484 {
 1485 /* true args */
 1486     struct vop_rmdir_args *ap = v;
 1487     struct vnode *dvp = ap->a_dvp;
 1488     struct cnode *dcp = VTOC(dvp);
 1489     struct vnode *vp = ap->a_vp;
 1490     struct componentname  *cnp = ap->a_cnp;
 1491     kauth_cred_t cred = cnp->cn_cred;
 1492     struct lwp *l = cnp->cn_lwp;
 1493 /* true args */
 1494     int error;
 1495     const char *nm = cnp->cn_nameptr;
 1496     int len = cnp->cn_namelen;
 1497     struct cnode *cp;
 1498 
 1499     MARK_ENTRY(CODA_RMDIR_STATS);
 1500 
 1501     /* Check for rmdir of control object. */
 1502     if (IS_CTL_NAME(dvp, nm, len)) {
 1503         MARK_INT_FAIL(CODA_RMDIR_STATS);
 1504         return(ENOENT);
 1505     }
 1506 
 1507     /* Can't remove . in self. */
 1508     if (dvp == vp) {
 1509         printf("coda_rmdir: dvp == vp\n");
 1510         error = EINVAL;
 1511         goto exit;
 1512     }
 1513 
 1514     /*
 1515      * The caller may not have adequate permissions, and the venus
 1516      * operation may fail, but it doesn't hurt from a correctness
 1517      * viewpoint to invalidate cache entries.
 1518      * XXX Why isn't this done after the venus_rmdir call?
 1519      */
 1520     /* Look up child in name cache (by name, from parent). */
 1521     cp = coda_nc_lookup(dcp, nm, len, cred);
 1522     /* If found, remove all children of the child (., ..). */
 1523     if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
 1524 
 1525     /* Remove child's own entry. */
 1526     coda_nc_zapfile(dcp, nm, len);
 1527 
 1528     /* Invalidate parent's attr cache (the modification time has changed). */
 1529     dcp->c_flags &= ~C_VATTR;
 1530 
 1531     error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, l);
 1532 
 1533     CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); )
 1534 
 1535 exit:
 1536     /* vput both vnodes */
 1537     vput(dvp);
 1538     if (dvp == vp) {
 1539         vrele(vp);
 1540     } else {
 1541         vput(vp);
 1542     }
 1543 
 1544     return(error);
 1545 }
 1546 
 1547 int
 1548 coda_symlink(void *v)
 1549 {
 1550 /* true args */
 1551     struct vop_symlink_args *ap = v;
 1552     struct vnode *dvp = ap->a_dvp;
 1553     struct cnode *dcp = VTOC(dvp);
 1554     /* a_vpp is used in place below */
 1555     struct componentname *cnp = ap->a_cnp;
 1556     struct vattr *tva = ap->a_vap;
 1557     char *path = ap->a_target;
 1558     kauth_cred_t cred = cnp->cn_cred;
 1559     struct lwp *l = cnp->cn_lwp;
 1560 /* locals */
 1561     int error;
 1562     u_long saved_cn_flags;
 1563     const char *nm = cnp->cn_nameptr;
 1564     int len = cnp->cn_namelen;
 1565     int plen = strlen(path);
 1566 
 1567     /*
 1568      * Here's the strategy for the moment: perform the symlink, then
 1569      * do a lookup to grab the resulting vnode.  I know this requires
 1570      * two communications with Venus for a new sybolic link, but
 1571      * that's the way the ball bounces.  I don't yet want to change
 1572      * the way the Mach symlink works.  When Mach support is
 1573      * deprecated, we should change symlink so that the common case
 1574      * returns the resultant vnode in a vpp argument.
 1575      */
 1576 
 1577     MARK_ENTRY(CODA_SYMLINK_STATS);
 1578 
 1579     /* Check for symlink of control object. */
 1580     if (IS_CTL_NAME(dvp, nm, len)) {
 1581         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1582         error = EACCES; 
 1583         goto exit;
 1584     }
 1585 
 1586     if (plen+1 > CODA_MAXPATHLEN) {
 1587         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1588         error = EINVAL;
 1589         goto exit;
 1590     }
 1591 
 1592     if (len+1 > CODA_MAXNAMLEN) {
 1593         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1594         error = EINVAL;
 1595         goto exit;
 1596     }
 1597 
 1598     error = venus_symlink(vtomi(dvp), &dcp->c_fid, path, plen, nm, len, tva, cred, l);
 1599 
 1600     /* Invalidate the parent's attr cache (modification time has changed). */
 1601     dcp->c_flags &= ~C_VATTR;
 1602 
 1603     if (!error) {
 1604         /*
 1605          * VOP_SYMLINK is not defined to pay attention to cnp->cn_flags;
 1606          * these are defined only for VOP_LOOKUP.   We desire to reuse
 1607          * cnp for a VOP_LOOKUP operation, and must be sure to not pass
 1608          * stray flags passed to us.  Such stray flags can occur because
 1609          * sys_symlink makes a namei call and then reuses the
 1610          * componentname structure.
 1611          */
 1612         /*
 1613          * XXX Arguably we should create our own componentname structure
 1614          * and not reuse the one that was passed in.
 1615          */
 1616         saved_cn_flags = cnp->cn_flags;
 1617         cnp->cn_flags &= ~(MODMASK | OPMASK);
 1618         cnp->cn_flags |= LOOKUP;
 1619         error = VOP_LOOKUP(dvp, ap->a_vpp, cnp);
 1620         cnp->cn_flags = saved_cn_flags;
 1621         /* Either an error occurs, or ap->a_vpp is locked. */
 1622     }
 1623 
 1624  exit:
 1625     /* unlock and deference parent */
 1626     vput(dvp);
 1627 
 1628     /* Per vnodeops(9), free name except on success and SAVESTART. */
 1629     if (error || (cnp->cn_flags & SAVESTART) == 0) {
 1630         PNBUF_PUT(cnp->cn_pnbuf);
 1631     }
 1632 
 1633     CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); )
 1634     return(error);
 1635 }
 1636 
 1637 /*
 1638  * Read directory entries.
 1639  */
 1640 int
 1641 coda_readdir(void *v)
 1642 {
 1643 /* true args */
 1644     struct vop_readdir_args *ap = v;
 1645     struct vnode *vp = ap->a_vp;
 1646     struct cnode *cp = VTOC(vp);
 1647     struct uio *uiop = ap->a_uio;
 1648     kauth_cred_t cred = ap->a_cred;
 1649     int *eofflag = ap->a_eofflag;
 1650     off_t **cookies = ap->a_cookies;
 1651     int *ncookies = ap->a_ncookies;
 1652 /* upcall decl */
 1653 /* locals */
 1654     struct lwp *l = curlwp;
 1655     int error = 0;
 1656 
 1657     MARK_ENTRY(CODA_READDIR_STATS);
 1658 
 1659     CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %lu, %lld)\n", uiop->uio_iov->iov_base, (unsigned long) uiop->uio_resid, (long long) uiop->uio_offset)); )
 1660 
 1661     /* Check for readdir of control object. */
 1662     if (IS_CTL_VP(vp)) {
 1663         MARK_INT_FAIL(CODA_READDIR_STATS);
 1664         return(ENOENT);
 1665     }
 1666 
 1667     {
 1668         /* Redirect the request to UFS. */
 1669 
 1670         /* If directory is not already open do an "internal open" on it. */
 1671         int opened_internally = 0;
 1672         if (cp->c_ovp == NULL) {
 1673             opened_internally = 1;
 1674             MARK_INT_GEN(CODA_OPEN_STATS);
 1675             error = VOP_OPEN(vp, FREAD, cred, l);
 1676 #ifdef  CODA_VERBOSE
 1677 printf("coda_readdir: Internally Opening %p\n", vp);
 1678 #endif
 1679             if (error) return(error);
 1680         } else
 1681             vp = cp->c_ovp;
 1682 
 1683         /* Have UFS handle the call. */
 1684         CODADEBUG(CODA_READDIR, myprintf((
 1685                                 "indirect readdir: fid = %s, refcnt = %d\n",
 1686                                 coda_f2s(&cp->c_fid), vp->v_usecount)); )
 1687         error = VOP_READDIR(vp, uiop, cred, eofflag, cookies, ncookies);
 1688         if (error)
 1689             MARK_INT_FAIL(CODA_READDIR_STATS);
 1690         else
 1691             MARK_INT_SAT(CODA_READDIR_STATS);
 1692 
 1693         /* Do an "internal close" if necessary. */
 1694         if (opened_internally) {
 1695             MARK_INT_GEN(CODA_CLOSE_STATS);
 1696             (void)VOP_CLOSE(vp, FREAD, cred, l);
 1697         }
 1698     }
 1699 
 1700     return(error);
 1701 }
 1702 
 1703 /*
 1704  * Convert from file system blocks to device blocks
 1705  */
 1706 int
 1707 coda_bmap(void *v)
 1708 {
 1709     /* XXX on the global proc */
 1710 /* true args */
 1711     struct vop_bmap_args *ap = v;
 1712     struct vnode *vp __attribute__((unused)) = ap->a_vp;        /* file's vnode */
 1713     daddr_t bn __attribute__((unused)) = ap->a_bn;      /* fs block number */
 1714     struct vnode **vpp = ap->a_vpp;                     /* RETURN vp of device */
 1715     daddr_t *bnp __attribute__((unused)) = ap->a_bnp;   /* RETURN device block number */
 1716     struct lwp *l __attribute__((unused)) = curlwp;
 1717 /* upcall decl */
 1718 /* locals */
 1719 
 1720         *vpp = (struct vnode *)0;
 1721         myprintf(("coda_bmap called!\n"));
 1722         return(EINVAL);
 1723 }
 1724 
 1725 /*
 1726  * I don't think the following two things are used anywhere, so I've
 1727  * commented them out
 1728  *
 1729  * struct buf *async_bufhead;
 1730  * int async_daemon_count;
 1731  */
 1732 int
 1733 coda_strategy(void *v)
 1734 {
 1735 /* true args */
 1736     struct vop_strategy_args *ap = v;
 1737     struct buf *bp __attribute__((unused)) = ap->a_bp;
 1738     struct lwp *l __attribute__((unused)) = curlwp;
 1739 /* upcall decl */
 1740 /* locals */
 1741 
 1742         myprintf(("coda_strategy called!  "));
 1743         return(EINVAL);
 1744 }
 1745 
 1746 int
 1747 coda_reclaim(void *v)
 1748 {
 1749 /* true args */
 1750     struct vop_reclaim_args *ap = v;
 1751     struct vnode *vp = ap->a_vp;
 1752     struct cnode *cp = VTOC(vp);
 1753 /* upcall decl */
 1754 /* locals */
 1755 
 1756 /*
 1757  * Forced unmount/flush will let vnodes with non zero use be destroyed!
 1758  */
 1759     ENTRY;
 1760 
 1761     if (IS_UNMOUNTING(cp)) {
 1762 #ifdef  DEBUG
 1763         if (VTOC(vp)->c_ovp) {
 1764             if (IS_UNMOUNTING(cp))
 1765                 printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp);
 1766         }
 1767 #endif
 1768     } else {
 1769 #ifdef OLD_DIAGNOSTIC
 1770         if (vp->v_usecount != 0)
 1771             print("coda_reclaim: pushing active %p\n", vp);
 1772         if (VTOC(vp)->c_ovp) {
 1773             panic("coda_reclaim: c_ovp not void");
 1774         }
 1775 #endif
 1776     }
 1777     cache_purge(vp);
 1778     coda_free(VTOC(vp));
 1779     SET_VTOC(vp) = NULL;
 1780     return (0);
 1781 }
 1782 
 1783 int
 1784 coda_lock(void *v)
 1785 {
 1786 /* true args */
 1787     struct vop_lock_args *ap = v;
 1788     struct vnode *vp = ap->a_vp;
 1789     struct cnode *cp = VTOC(vp);
 1790 /* upcall decl */
 1791 /* locals */
 1792 
 1793     ENTRY;
 1794 
 1795     if (coda_lockdebug) {
 1796         myprintf(("Attempting lock on %s\n",
 1797                   coda_f2s(&cp->c_fid)));
 1798     }
 1799 
 1800     return (lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock));
 1801 }
 1802 
 1803 int
 1804 coda_unlock(void *v)
 1805 {
 1806 /* true args */
 1807     struct vop_unlock_args *ap = v;
 1808     struct vnode *vp = ap->a_vp;
 1809     struct cnode *cp = VTOC(vp);
 1810 /* upcall decl */
 1811 /* locals */
 1812 
 1813     ENTRY;
 1814     if (coda_lockdebug) {
 1815         myprintf(("Attempting unlock on %s\n",
 1816                   coda_f2s(&cp->c_fid)));
 1817     }
 1818 
 1819     return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock));
 1820 }
 1821 
 1822 int
 1823 coda_islocked(void *v)
 1824 {
 1825 /* true args */
 1826     struct vop_islocked_args *ap = v;
 1827     ENTRY;
 1828 
 1829     return (lockstatus(&ap->a_vp->v_lock));
 1830 }
 1831 
 1832 /*
 1833  * Given a device and inode, obtain a locked vnode.  One reference is
 1834  * obtained and passed back to the caller.
 1835  */
 1836 int
 1837 coda_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp)
 1838 {
 1839     int           error;
 1840     struct mount *mp;
 1841 
 1842     /* Obtain mount point structure from device. */
 1843     if (!(mp = devtomp(dev))) {
 1844         myprintf(("coda_grab_vnode: devtomp(%d) returns NULL\n", dev));
 1845         return(ENXIO);
 1846     }
 1847 
 1848     /*
 1849      * Obtain vnode from mount point and inode.
 1850      * XXX VFS_VGET does not clearly define locked/referenced state of
 1851      * returned vnode.
 1852      */
 1853     error = VFS_VGET(mp, ino, vpp);
 1854     if (error) {
 1855         myprintf(("coda_grab_vnode: iget/vget(%d, %llu) returns %p, err %d\n",
 1856                   dev, (unsigned long long)ino, *vpp, error));
 1857         return(ENOENT);
 1858     }
 1859     return(0);
 1860 }
 1861 
 1862 void
 1863 print_vattr(struct vattr *attr)
 1864 {
 1865     const char *typestr;
 1866 
 1867     switch (attr->va_type) {
 1868     case VNON:
 1869         typestr = "VNON";
 1870         break;
 1871     case VREG:
 1872         typestr = "VREG";
 1873         break;
 1874     case VDIR:
 1875         typestr = "VDIR";
 1876         break;
 1877     case VBLK:
 1878         typestr = "VBLK";
 1879         break;
 1880     case VCHR:
 1881         typestr = "VCHR";
 1882         break;
 1883     case VLNK:
 1884         typestr = "VLNK";
 1885         break;
 1886     case VSOCK:
 1887         typestr = "VSCK";
 1888         break;
 1889     case VFIFO:
 1890         typestr = "VFFO";
 1891         break;
 1892     case VBAD:
 1893         typestr = "VBAD";
 1894         break;
 1895     default:
 1896         typestr = "????";
 1897         break;
 1898     }
 1899 
 1900 
 1901     myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
 1902               typestr, (int)attr->va_mode, (int)attr->va_uid,
 1903               (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
 1904 
 1905     myprintf(("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
 1906               (int)attr->va_fileid, (int)attr->va_nlink,
 1907               (int)attr->va_size,
 1908               (int)attr->va_blocksize,(int)attr->va_bytes));
 1909     myprintf(("      gen %ld flags %ld vaflags %d\n",
 1910               attr->va_gen, attr->va_flags, attr->va_vaflags));
 1911     myprintf(("      atime sec %d nsec %d\n",
 1912               (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec));
 1913     myprintf(("      mtime sec %d nsec %d\n",
 1914               (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec));
 1915     myprintf(("      ctime sec %d nsec %d\n",
 1916               (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec));
 1917 }
 1918 
 1919 /* How to print a ucred */
 1920 void
 1921 print_cred(kauth_cred_t cred)
 1922 {
 1923 
 1924         uint16_t ngroups;
 1925         int i;
 1926 
 1927         myprintf(("ref %d\tuid %d\n", kauth_cred_getrefcnt(cred),
 1928                  kauth_cred_geteuid(cred)));
 1929 
 1930         ngroups = kauth_cred_ngroups(cred);
 1931         for (i=0; i < ngroups; i++)
 1932                 myprintf(("\tgroup %d: (%d)\n", i, kauth_cred_group(cred, i)));
 1933         myprintf(("\n"));
 1934 
 1935 }
 1936 
 1937 /*
 1938  * Return a vnode for the given fid.
 1939  * If no cnode exists for this fid create one and put it
 1940  * in a table hashed by coda_f2i().  If the cnode for
 1941  * this fid is already in the table return it (ref count is
 1942  * incremented by coda_find.  The cnode will be flushed from the
 1943  * table when coda_inactive calls coda_unsave.
 1944  */
 1945 struct cnode *
 1946 make_coda_node(CodaFid *fid, struct mount *vfsp, short type)
 1947 {
 1948     struct cnode *cp;
 1949     int          err;
 1950 
 1951     if ((cp = coda_find(fid)) == NULL) {
 1952         struct vnode *vp;
 1953 
 1954         cp = coda_alloc();
 1955         cp->c_fid = *fid;
 1956 
 1957         err = getnewvnode(VT_CODA, vfsp, coda_vnodeop_p, &vp);
 1958         if (err) {
 1959             panic("coda: getnewvnode returned error %d", err);
 1960         }
 1961         vp->v_data = cp;
 1962         vp->v_type = type;
 1963         cp->c_vnode = vp;
 1964         coda_save(cp);
 1965 
 1966     } else {
 1967         vref(CTOV(cp));
 1968     }
 1969 
 1970     return cp;
 1971 }
 1972 
 1973 /*
 1974  * coda_getpages may be called on a vnode which has not been opened,
 1975  * e.g. to fault in pages to execute a program.  In that case, we must
 1976  * open the file to get the container.  The vnode may or may not be
 1977  * locked, and we must leave it in the same state.
 1978  * XXX The protocol requires v_uobj.vmobjlock to be
 1979  * held by caller, but this isn't documented in vnodeops(9) or vnode_if.src.
 1980  */
 1981 int
 1982 coda_getpages(void *v)
 1983 {
 1984         struct vop_getpages_args /* {
 1985                 struct vnode *a_vp;
 1986                 voff_t a_offset;
 1987                 struct vm_page **a_m;
 1988                 int *a_count;
 1989                 int a_centeridx;
 1990                 vm_prot_t a_access_type;
 1991                 int a_advice;
 1992                 int a_flags;
 1993         } */ *ap = v;
 1994         struct vnode *vp = ap->a_vp;
 1995         struct cnode *cp = VTOC(vp);
 1996         struct lwp *l = curlwp;
 1997         kauth_cred_t cred = l->l_cred;
 1998         int error, cerror;
 1999         int waslocked;         /* 1 if vnode lock was held on entry */
 2000         int didopen = 0;        /* 1 if we opened container file */
 2001 
 2002         /*
 2003          * Handle a case that uvm_fault doesn't quite use yet.
 2004          * See layer_vnops.c. for inspiration.
 2005          */
 2006         if (ap->a_flags & PGO_LOCKED) {
 2007                 return EBUSY;
 2008         }
 2009 
 2010         /* Check for control object. */
 2011         if (IS_CTL_VP(vp)) {
 2012                 printf("coda_getpages: control object %p\n", vp);
 2013                 simple_unlock(&vp->v_uobj.vmobjlock);
 2014                 return(EINVAL);
 2015         }
 2016 
 2017         /*
 2018          * XXX It's really not ok to be releasing the lock we get,
 2019          * because we could be overlapping with another call to
 2020          * getpages and drop a lock they are relying on.  We need to
 2021          * figure out whether getpages ever is called holding the
 2022          * lock, and if we should serialize getpages calls by some
 2023          * mechanism.
 2024          */
 2025         waslocked = VOP_ISLOCKED(vp);
 2026 
 2027         /* Drop the vmobject lock. */
 2028         simple_unlock(&vp->v_uobj.vmobjlock);
 2029 
 2030         /* Get container file if not already present. */
 2031         if (cp->c_ovp == NULL) {
 2032                 /*
 2033                  * VOP_OPEN requires a locked vnode.  We must avoid
 2034                  * locking the vnode if it is already locked, and
 2035                  * leave it in the same state on exit.
 2036                  */
 2037                 if (waslocked == 0) {
 2038                         cerror = vn_lock(vp, LK_EXCLUSIVE);
 2039                         if (cerror) {
 2040                                 printf("coda_getpages: can't lock vnode %p\n",
 2041                                        vp);
 2042                                 return cerror;
 2043                         }
 2044 #if 0
 2045                         printf("coda_getpages: locked vnode %p\n", vp);
 2046 #endif
 2047                 }
 2048 
 2049                 /*
 2050                  * Open file (causes upcall to venus).
 2051                  * XXX Perhaps we should not fully open the file, but
 2052                  * simply obtain a container file.
 2053                  */
 2054                 /* XXX Is it ok to do this while holding the simplelock? */
 2055                 cerror = VOP_OPEN(vp, FREAD, cred, l);
 2056 
 2057                 if (cerror) {
 2058                         printf("coda_getpages: cannot open vnode %p => %d\n",
 2059                                vp, cerror);
 2060                         if (waslocked == 0)
 2061                                 VOP_UNLOCK(vp, 0);
 2062                         return cerror;
 2063                 }
 2064 
 2065 #if 0
 2066                 printf("coda_getpages: opened vnode %p\n", vp);
 2067 #endif
 2068                 didopen = 1;
 2069         }
 2070         KASSERT(cp->c_ovp != NULL);
 2071 
 2072         /* Munge the arg structure to refer to the container vnode. */
 2073         ap->a_vp = cp->c_ovp;
 2074 
 2075         /* Get the lock on the container vnode, and call getpages on it. */
 2076         simple_lock(&ap->a_vp->v_uobj.vmobjlock);
 2077         error = VCALL(ap->a_vp, VOFFSET(vop_getpages), ap);
 2078 
 2079         /* If we opened the vnode, we must close it. */
 2080         if (didopen) {
 2081                 /*
 2082                  * VOP_CLOSE requires a locked vnode, but we are still
 2083                  * holding the lock (or riding a caller's lock).
 2084                  */
 2085                 cerror = VOP_CLOSE(vp, FREAD, cred, l);
 2086                 if (cerror != 0)
 2087                         /* XXX How should we handle this? */
 2088                         printf("coda_getpages: closed vnode %p -> %d\n",
 2089                                vp, cerror);
 2090 
 2091                 /* If we obtained a lock, drop it. */
 2092                 if (waslocked == 0)
 2093                         VOP_UNLOCK(vp, 0);
 2094         }
 2095 
 2096         return error;
 2097 }
 2098 
 2099 /*
 2100  * The protocol requires v_uobj.vmobjlock to be held by the caller, as
 2101  * documented in vnodeops(9).  XXX vnode_if.src doesn't say this.
 2102  */
 2103 int
 2104 coda_putpages(void *v)
 2105 {
 2106         struct vop_putpages_args /* {
 2107                 struct vnode *a_vp;
 2108                 voff_t a_offlo;
 2109                 voff_t a_offhi;
 2110                 int a_flags;
 2111         } */ *ap = v;
 2112         struct vnode *vp = ap->a_vp;
 2113         struct cnode *cp = VTOC(vp);
 2114         int error;
 2115 
 2116         /* Drop the vmobject lock. */
 2117         simple_unlock(&vp->v_uobj.vmobjlock);
 2118 
 2119         /* Check for control object. */
 2120         if (IS_CTL_VP(vp)) {
 2121                 printf("coda_putpages: control object %p\n", vp);
 2122                 return(EINVAL);
 2123         }
 2124 
 2125         /*
 2126          * If container object is not present, then there are no pages
 2127          * to put; just return without error.  This happens all the
 2128          * time, apparently during discard of a closed vnode (which
 2129          * trivially can't have dirty pages).
 2130          */
 2131         if (cp->c_ovp == NULL)
 2132                 return 0;
 2133 
 2134         /* Munge the arg structure to refer to the container vnode. */
 2135         ap->a_vp = cp->c_ovp;
 2136 
 2137         /* Get the lock on the container vnode, and call putpages on it. */
 2138         simple_lock(&ap->a_vp->v_uobj.vmobjlock);
 2139         error = VCALL(ap->a_vp, VOFFSET(vop_putpages), ap);
 2140 
 2141         return error;
 2142 }

Cache object: b9b65b9cb3de1d6a14dc655e51eab2a6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.