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 /*-
    2  *             Coda: an Experimental Distributed File System
    3  *                              Release 3.1
    4  * 
    5  *           Copyright (c) 1987-1998 Carnegie Mellon University
    6  *                          All Rights Reserved
    7  * 
    8  * Permission  to  use, copy, modify and distribute this software and its
    9  * documentation is hereby granted,  provided  that  both  the  copyright
   10  * notice  and  this  permission  notice  appear  in  all  copies  of the
   11  * software, derivative works or  modified  versions,  and  any  portions
   12  * thereof, and that both notices appear in supporting documentation, and
   13  * that credit is given to Carnegie Mellon University  in  all  documents
   14  * and publicity pertaining to direct or indirect use of this code or its
   15  * derivatives.
   16  * 
   17  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
   18  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
   19  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
   20  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
   21  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
   22  * ANY DERIVATIVE WORK.
   23  * 
   24  * Carnegie  Mellon  encourages  users  of  this  software  to return any
   25  * improvements or extensions that  they  make,  and  to  grant  Carnegie
   26  * Mellon the rights to redistribute these changes without encumbrance.
   27  * 
   28  *      @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
   29  */
   30 /* 
   31  * Mach Operating System
   32  * Copyright (c) 1990 Carnegie-Mellon University
   33  * Copyright (c) 1989 Carnegie-Mellon University
   34  * All rights reserved.  The CMU software License Agreement specifies
   35  * the terms and conditions for use and redistribution.
   36  */
   37 
   38 /*
   39  * This code was written for the Coda filesystem at Carnegie Mellon
   40  * University.  Contributers include David Steere, James Kistler, and
   41  * M. Satyanarayanan.  
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __FBSDID("$FreeBSD: releng/6.0/sys/coda/coda_vnops.c 145006 2005-04-13 10:59:09Z jeff $");
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/acct.h>
   50 #include <sys/errno.h>
   51 #include <sys/fcntl.h>
   52 #include <sys/kernel.h>
   53 #include <sys/lock.h>
   54 #include <sys/malloc.h>
   55 #include <sys/file.h>           /* Must come after sys/malloc.h */
   56 #include <sys/mount.h>
   57 #include <sys/mutex.h>
   58 #include <sys/namei.h>
   59 #include <sys/proc.h>
   60 #include <sys/uio.h>
   61 #include <sys/unistd.h>
   62 
   63 #include <vm/vm.h>
   64 #include <vm/vm_object.h>
   65 #include <vm/vm_extern.h>
   66 
   67 #include <coda/coda.h>
   68 #include <coda/cnode.h>
   69 #include <coda/coda_vnops.h>
   70 #include <coda/coda_venus.h>
   71 #include <coda/coda_opstats.h>
   72 #include <coda/coda_subr.h>
   73 #include <coda/coda_namecache.h>
   74 #include <coda/coda_pioctl.h>
   75 
   76 /* 
   77  * These flags select various performance enhancements.
   78  */
   79 int coda_attr_cache  = 1;       /* Set to cache attributes in the kernel */
   80 int coda_symlink_cache = 1;     /* Set to cache symbolic link information */
   81 int coda_access_cache = 1;      /* Set to handle some access checks directly */
   82 
   83 /* structure to keep track of vfs calls */
   84 
   85 struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
   86 
   87 #define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++)
   88 #define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++)
   89 #define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++)
   90 #define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++)
   91 
   92 /* What we are delaying for in printf */
   93 int coda_printf_delay = 0;  /* in microseconds */
   94 int coda_vnop_print_entry = 0;
   95 static int coda_lockdebug = 0;
   96 
   97 /*
   98  * Some NetBSD details:
   99  * 
  100  *   coda_start is called at the end of the mount syscall.
  101  *   coda_init is called at boot time.
  102  */
  103 
  104 #define ENTRY  if(coda_vnop_print_entry) myprintf(("Entered %s\n",__func__))
  105 
  106 /* Definition of the vnode operation vector */
  107 
  108 struct vop_vector coda_vnodeops = {
  109     .vop_default = VOP_PANIC,
  110     .vop_lookup = coda_lookup,          /* lookup */
  111     .vop_create = coda_create,          /* create */
  112     .vop_mknod = VOP_PANIC,     /* mknod */
  113     .vop_open = coda_open,              /* open */
  114     .vop_close = coda_close,            /* close */
  115     .vop_access = coda_access,          /* access */
  116     .vop_getattr = coda_getattr,        /* getattr */
  117     .vop_setattr = coda_setattr,        /* setattr */
  118     .vop_read = coda_read,              /* read */
  119     .vop_write = coda_write,            /* write */
  120     .vop_ioctl = coda_ioctl,            /* ioctl */
  121     .vop_fsync = coda_fsync,            /* fsync */
  122     .vop_remove = coda_remove,          /* remove */
  123     .vop_link = coda_link,              /* link */
  124     .vop_rename = coda_rename,          /* rename */
  125     .vop_mkdir = coda_mkdir,            /* mkdir */
  126     .vop_rmdir = coda_rmdir,            /* rmdir */
  127     .vop_symlink = coda_symlink,        /* symlink */
  128     .vop_readdir = coda_readdir,        /* readdir */
  129     .vop_readlink = coda_readlink,      /* readlink */
  130     .vop_inactive = coda_inactive,      /* inactive */
  131     .vop_reclaim = coda_reclaim,        /* reclaim */
  132     .vop_lock = coda_lock,              /* lock */
  133     .vop_unlock = coda_unlock,          /* unlock */
  134     .vop_bmap = coda_bmap,              /* bmap */
  135     .vop_print = VOP_PANIC,     /* print */
  136     .vop_islocked = coda_islocked,      /* islocked */
  137     .vop_pathconf = coda_pathconf,      /* pathconf */
  138     .vop_advlock = VOP_NULL,    /* advlock */
  139     .vop_lease = VOP_NULL,              /* lease */
  140     .vop_poll = vop_stdpoll,
  141     .vop_getpages = vop_stdgetpages,    /* pager intf.*/
  142     .vop_putpages = vop_stdputpages,    /* pager intf.*/
  143     .vop_getwritemount =        vop_stdgetwritemount,
  144 
  145 #if 0
  146     missing
  147     .vop_cachedlookup = ufs_lookup,
  148     .vop_whiteout =     ufs_whiteout,
  149 #endif
  150 
  151 };
  152 
  153 /* A generic do-nothing.  For lease_check, advlock */
  154 int
  155 coda_vop_nop(void *anon) {
  156     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
  157 
  158     if (codadebug) {
  159         myprintf(("Vnode operation %s called, but unsupported\n",
  160                   (*desc)->vdesc_name));
  161     } 
  162    return (0);
  163 }
  164 
  165 int
  166 coda_vnodeopstats_init(void)
  167 {
  168         register int i;
  169         
  170         for(i=0;i<CODA_VNODEOPS_SIZE;i++) {
  171                 coda_vnodeopstats[i].opcode = i;
  172                 coda_vnodeopstats[i].entries = 0;
  173                 coda_vnodeopstats[i].sat_intrn = 0;
  174                 coda_vnodeopstats[i].unsat_intrn = 0;
  175                 coda_vnodeopstats[i].gen_intrn = 0;
  176         }
  177         return 0;
  178 }
  179                 
  180 /* 
  181  * coda_open calls Venus to return the device, inode pair of the cache
  182  * file holding the data. Using iget, coda_open finds the vnode of the
  183  * cache file, and then opens it.
  184  */
  185 int
  186 coda_open(struct vop_open_args *ap)
  187 {
  188     /* 
  189      * NetBSD can pass the O_EXCL flag in mode, even though the check
  190      * has already happened.  Venus defensively assumes that if open
  191      * is passed the EXCL, it must be a bug.  We strip the flag here.
  192      */
  193 /* true args */
  194     register struct vnode **vpp = &(ap->a_vp);
  195     struct cnode *cp = VTOC(*vpp);
  196     int flag = ap->a_mode & (~O_EXCL);
  197     struct ucred *cred = ap->a_cred;
  198     struct thread *td = ap->a_td;
  199 /* locals */
  200     int error;
  201     struct vnode *vp;
  202     struct cdev *dev;
  203     ino_t inode;
  204 
  205     MARK_ENTRY(CODA_OPEN_STATS);
  206 
  207     /* Check for open of control file. */
  208     if (IS_CTL_VP(*vpp)) {
  209         /* XXX */
  210         /* if (WRITEABLE(flag)) */ 
  211         if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
  212             MARK_INT_FAIL(CODA_OPEN_STATS);
  213             return(EACCES);
  214         }
  215         MARK_INT_SAT(CODA_OPEN_STATS);
  216         return(0);
  217     }
  218 
  219     error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, td->td_proc, &dev, &inode);
  220     if (error)
  221         return (error);
  222     if (!error) {
  223         CODADEBUG( CODA_OPEN,myprintf(("open: dev %#lx inode %lu result %d\n",
  224                                        (u_long)dev2udev(dev), (u_long)inode,
  225                                        error)); )
  226     }
  227 
  228     /* Translate the <device, inode> pair for the cache file into
  229        an inode pointer. */
  230     error = coda_grab_vnode(dev, inode, &vp);
  231     if (error)
  232         return (error);
  233 
  234     /* We get the vnode back locked.  Needs unlocked */
  235     VOP_UNLOCK(vp, 0, td);
  236     /* Keep a reference until the close comes in. */
  237     vref(*vpp);                
  238 
  239     /* Save the vnode pointer for the cache file. */
  240     if (cp->c_ovp == NULL) {
  241         cp->c_ovp = vp;
  242     } else {
  243         if (cp->c_ovp != vp)
  244             panic("coda_open:  cp->c_ovp != ITOV(ip)");
  245     }
  246     cp->c_ocount++;
  247 
  248     /* Flush the attribute cached if writing the file. */
  249     if (flag & FWRITE) {
  250         cp->c_owrite++;
  251         cp->c_flags &= ~C_VATTR;
  252     }
  253 
  254     /* Save the <device, inode> pair for the cache file to speed
  255        up subsequent page_read's. */
  256     cp->c_device = dev;
  257     cp->c_inode = inode;
  258 
  259     /* Open the cache file. */
  260     error = VOP_OPEN(vp, flag, cred, td, -1); 
  261     if (error) {
  262         printf("coda_open: VOP_OPEN on container failed %d\n", error);
  263         return (error);
  264     }
  265 /* grab (above) does this when it calls newvnode unless it's in the cache*/
  266 
  267     return(error);
  268 }
  269 
  270 /*
  271  * Close the cache file used for I/O and notify Venus.
  272  */
  273 int
  274 coda_close(struct vop_close_args *ap)
  275 {
  276 /* true args */
  277     struct vnode *vp = ap->a_vp;
  278     struct cnode *cp = VTOC(vp);
  279     int flag = ap->a_fflag;
  280     struct ucred *cred = ap->a_cred;
  281     struct thread *td = ap->a_td;
  282 /* locals */
  283     int error;
  284 
  285     MARK_ENTRY(CODA_CLOSE_STATS);
  286 
  287     /* Check for close of control file. */
  288     if (IS_CTL_VP(vp)) {
  289         MARK_INT_SAT(CODA_CLOSE_STATS);
  290         return(0);
  291     }
  292 
  293     if (IS_UNMOUNTING(cp)) {
  294         if (cp->c_ovp) {
  295 #ifdef  CODA_VERBOSE
  296             printf("coda_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n",
  297                     vrefcnt(vp), cp->c_ovp, vp, cp);
  298 #endif
  299 #ifdef  hmm
  300             vgone(cp->c_ovp);
  301 #else
  302             VOP_CLOSE(cp->c_ovp, flag, cred, td); /* Do errors matter here? */
  303             vrele(cp->c_ovp);
  304 #endif
  305         } else {
  306 #ifdef  CODA_VERBOSE
  307             printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
  308 #endif
  309         }
  310         return ENODEV;
  311     } else {
  312         VOP_CLOSE(cp->c_ovp, flag, cred, td); /* Do errors matter here? */
  313         vrele(cp->c_ovp);
  314     }
  315 
  316     if (--cp->c_ocount == 0)
  317         cp->c_ovp = NULL;
  318 
  319     if (flag & FWRITE)                    /* file was opened for write */
  320         --cp->c_owrite;
  321 
  322     error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, td->td_proc);
  323     vrele(CTOV(cp));
  324 
  325     CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); )
  326     return(error);
  327 }
  328 
  329 int
  330 coda_read(struct vop_read_args *ap)
  331 {
  332 
  333     ENTRY;
  334     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ,
  335                     ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td));
  336 }
  337 
  338 int
  339 coda_write(struct vop_write_args *ap)
  340 {
  341 
  342     ENTRY;
  343     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE,
  344                     ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td));
  345 }
  346 
  347 int
  348 coda_rdwr(vp, uiop, rw, ioflag, cred, td)
  349     struct vnode *vp;
  350     struct uio *uiop;
  351     enum uio_rw rw;
  352     int ioflag;
  353     struct ucred *cred;
  354     struct thread *td;
  355 { 
  356 /* upcall decl */
  357   /* NOTE: container file operation!!! */
  358 /* locals */
  359     struct cnode *cp = VTOC(vp);
  360     struct vnode *cfvp = cp->c_ovp;
  361     struct proc *p = td->td_proc;
  362     struct thread *ltd = td;
  363     int igot_internally = 0;
  364     int opened_internally = 0;
  365     int error = 0;
  366     int iscore = 0;
  367 
  368     MARK_ENTRY(CODA_RDWR_STATS);
  369 
  370     CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %d, %lld, %d)\n", rw, 
  371                               (void *)uiop->uio_iov->iov_base, uiop->uio_resid, 
  372                               (long long)uiop->uio_offset, uiop->uio_segflg)); )
  373         
  374     /* Check for rdwr of control object. */
  375     if (IS_CTL_VP(vp)) {
  376         MARK_INT_FAIL(CODA_RDWR_STATS);
  377         return(EINVAL);
  378     }
  379 
  380     /* 
  381      * If file is not already open this must be a page
  382      * {read,write} request.  Iget the cache file's inode
  383      * pointer if we still have its <device, inode> pair.
  384      * Otherwise, we must do an internal open to derive the
  385      * pair. 
  386      */
  387     if (cfvp == NULL) {
  388         /* 
  389          * If we're dumping core, do the internal open. Otherwise
  390          * venus won't have the correct size of the core when
  391          * it's completely written.
  392          */
  393         if (p) {
  394             PROC_LOCK(p);
  395             iscore = (p->p_acflag & ACORE);
  396             PROC_UNLOCK(p);
  397         }
  398         else
  399             ltd = curthread; 
  400 
  401         if (cp->c_inode != 0 && !iscore) {
  402             igot_internally = 1;
  403             error = coda_grab_vnode(cp->c_device, cp->c_inode, &cfvp);
  404             if (error) {
  405                 MARK_INT_FAIL(CODA_RDWR_STATS);
  406                 return(error);
  407             }
  408             /* 
  409              * We get the vnode back locked by curthread in both Mach and
  410              * NetBSD.  Needs unlocked 
  411              */
  412             VOP_UNLOCK(cfvp, 0, ltd);
  413         }
  414         else {
  415             opened_internally = 1;
  416             MARK_INT_GEN(CODA_OPEN_STATS);
  417             error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), 
  418                              cred, td, -1);
  419 printf("coda_rdwr: Internally Opening %p\n", vp);
  420             if (error) {
  421                 printf("coda_rdwr: VOP_OPEN on container failed %d\n", error);
  422                 return (error);
  423             }
  424             cfvp = cp->c_ovp;
  425         }
  426     }
  427 
  428     /* Have UFS handle the call. */
  429     CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = %s, refcnt = %d\n",
  430                              coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); )
  431     if (rw == UIO_READ) {
  432         error = VOP_READ(cfvp, uiop, ioflag, cred);
  433     } else {
  434         error = VOP_WRITE(cfvp, uiop, ioflag, cred);
  435         /* ufs_write updates the vnode_pager_setsize for the vnode/object */
  436 
  437         {   struct vattr attr;
  438 
  439             if (VOP_GETATTR(cfvp, &attr, cred, td) == 0) {
  440                 vnode_pager_setsize(vp, attr.va_size);
  441             }
  442         }
  443     }
  444 
  445     if (error)
  446         MARK_INT_FAIL(CODA_RDWR_STATS);
  447     else
  448         MARK_INT_SAT(CODA_RDWR_STATS);
  449 
  450     /* Do an internal close if necessary. */
  451     if (opened_internally) {
  452         MARK_INT_GEN(CODA_CLOSE_STATS);
  453         (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, td);
  454     }
  455 
  456     /* Invalidate cached attributes if writing. */
  457     if (rw == UIO_WRITE)
  458         cp->c_flags &= ~C_VATTR;
  459     return(error);
  460 }
  461 
  462 
  463 
  464 int
  465 coda_ioctl(struct vop_ioctl_args *ap)
  466 {
  467 /* true args */
  468     struct vnode *vp = ap->a_vp;
  469     int com = ap->a_command;
  470     caddr_t data = ap->a_data;
  471     int flag = ap->a_fflag;
  472     struct ucred *cred = ap->a_cred;
  473     struct thread *td = ap->a_td;
  474 /* locals */
  475     int error;
  476     struct vnode *tvp;
  477     struct nameidata ndp;
  478     struct PioctlData *iap = (struct PioctlData *)data;
  479 
  480     MARK_ENTRY(CODA_IOCTL_STATS);
  481 
  482     CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));)
  483         
  484     /* Don't check for operation on a dying object, for ctlvp it
  485        shouldn't matter */
  486         
  487     /* Must be control object to succeed. */
  488     if (!IS_CTL_VP(vp)) {
  489         MARK_INT_FAIL(CODA_IOCTL_STATS);
  490         CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));)
  491             return (EOPNOTSUPP);
  492     }
  493     /* Look up the pathname. */
  494 
  495     /* Should we use the name cache here? It would get it from
  496        lookupname sooner or later anyway, right? */
  497 
  498     NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, iap->path, td);
  499     error = namei(&ndp);
  500     tvp = ndp.ni_vp;
  501 
  502     if (error) {
  503         MARK_INT_FAIL(CODA_IOCTL_STATS);
  504         CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n",
  505                                    error));)
  506         return(error);
  507     }
  508 
  509     /* 
  510      * Make sure this is a coda style cnode, but it may be a
  511      * different vfsp 
  512      */
  513     if (tvp->v_op != &coda_vnodeops) {
  514         vrele(tvp);
  515         NDFREE(&ndp, NDF_ONLY_PNBUF);
  516         MARK_INT_FAIL(CODA_IOCTL_STATS);
  517         CODADEBUG(CODA_IOCTL, 
  518                  myprintf(("coda_ioctl error: %s not a coda object\n", 
  519                         iap->path));)
  520         return(EINVAL);
  521     }
  522 
  523     if (iap->vi.in_size > VC_MAXDATASIZE) {
  524         NDFREE(&ndp, 0);
  525         return(EINVAL);
  526     }
  527     error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, td->td_proc);
  528 
  529     if (error)
  530         MARK_INT_FAIL(CODA_IOCTL_STATS);
  531     else
  532         CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); )
  533 
  534     vrele(tvp);
  535     NDFREE(&ndp, NDF_ONLY_PNBUF);
  536     return(error);
  537 }
  538 
  539 /*
  540  * To reduce the cost of a user-level venus;we cache attributes in
  541  * the kernel.  Each cnode has storage allocated for an attribute. If
  542  * c_vattr is valid, return a reference to it. Otherwise, get the
  543  * attributes from venus and store them in the cnode.  There is some
  544  * question if this method is a security leak. But I think that in
  545  * order to make this call, the user must have done a lookup and
  546  * opened the file, and therefore should already have access.  
  547  */
  548 int
  549 coda_getattr(struct vop_getattr_args *ap)
  550 {
  551 /* true args */
  552     struct vnode *vp = ap->a_vp;
  553     struct cnode *cp = VTOC(vp);
  554     struct vattr *vap = ap->a_vap;
  555     struct ucred *cred = ap->a_cred;
  556     struct thread *td = ap->a_td;
  557 /* locals */
  558     int error;
  559 
  560     MARK_ENTRY(CODA_GETATTR_STATS);
  561 
  562     if (IS_UNMOUNTING(cp))
  563         return ENODEV;
  564 
  565     /* Check for getattr of control object. */
  566     if (IS_CTL_VP(vp)) {
  567         MARK_INT_FAIL(CODA_GETATTR_STATS);
  568         return(ENOENT);
  569     }
  570 
  571     /* Check to see if the attributes have already been cached */
  572     if (VALID_VATTR(cp)) { 
  573         CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: %s\n",
  574                                         coda_f2s(&cp->c_fid)));});
  575         CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
  576                  print_vattr(&cp->c_vattr); );
  577         
  578         *vap = cp->c_vattr;
  579         MARK_INT_SAT(CODA_GETATTR_STATS);
  580         return(0);
  581     }
  582 
  583     error = venus_getattr(vtomi(vp), &cp->c_fid, cred, td->td_proc, vap);
  584 
  585     if (!error) {
  586         CODADEBUG(CODA_GETATTR, myprintf(("getattr miss %s: result %d\n",
  587                                      coda_f2s(&cp->c_fid), error)); )          
  588             
  589         CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
  590                  print_vattr(vap);      );
  591         
  592     {   int size = vap->va_size;
  593         struct vnode *convp = cp->c_ovp;
  594         if (convp != (struct vnode *)0) {
  595             vnode_pager_setsize(convp, size);
  596         }
  597     }
  598         /* If not open for write, store attributes in cnode */   
  599         if ((cp->c_owrite == 0) && (coda_attr_cache)) {  
  600             cp->c_vattr = *vap;
  601             cp->c_flags |= C_VATTR; 
  602         }
  603         
  604     }
  605     return(error);
  606 }
  607 
  608 int
  609 coda_setattr(struct vop_setattr_args *ap)
  610 {
  611 /* true args */
  612     register struct vnode *vp = ap->a_vp;
  613     struct cnode *cp = VTOC(vp);
  614     register struct vattr *vap = ap->a_vap;
  615     struct ucred *cred = ap->a_cred;
  616     struct thread *td = ap->a_td;
  617 /* locals */
  618     int error;
  619 
  620     MARK_ENTRY(CODA_SETATTR_STATS);
  621 
  622     /* Check for setattr of control object. */
  623     if (IS_CTL_VP(vp)) {
  624         MARK_INT_FAIL(CODA_SETATTR_STATS);
  625         return(ENOENT);
  626     }
  627 
  628     if (codadebug & CODADBGMSK(CODA_SETATTR)) {
  629         print_vattr(vap);
  630     }
  631     error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, td->td_proc);
  632 
  633     if (!error)
  634         cp->c_flags &= ~C_VATTR;
  635 
  636     {   int size = vap->va_size;
  637         struct vnode *convp = cp->c_ovp;
  638         if (size != VNOVAL && convp != (struct vnode *)0) {
  639             vnode_pager_setsize(convp, size);
  640         }
  641     }
  642     CODADEBUG(CODA_SETATTR,     myprintf(("setattr %d\n", error)); )
  643     return(error);
  644 }
  645 
  646 int
  647 coda_access(struct vop_access_args *ap)
  648 {
  649 /* true args */
  650     struct vnode *vp = ap->a_vp;
  651     struct cnode *cp = VTOC(vp);
  652     int mode = ap->a_mode;
  653     struct ucred *cred = ap->a_cred;
  654     struct thread *td = ap->a_td;
  655 /* locals */
  656     int error;
  657 
  658     MARK_ENTRY(CODA_ACCESS_STATS);
  659 
  660     /* Check for access of control object.  Only read access is
  661        allowed on it. */
  662     if (IS_CTL_VP(vp)) {
  663         /* bogus hack - all will be marked as successes */
  664         MARK_INT_SAT(CODA_ACCESS_STATS);
  665         return(((mode & VREAD) && !(mode & (VWRITE | VEXEC))) 
  666                ? 0 : EACCES);
  667     }
  668 
  669     /*
  670      * if the file is a directory, and we are checking exec (eg lookup) 
  671      * access, and the file is in the namecache, then the user must have 
  672      * lookup access to it.
  673      */
  674     if (coda_access_cache) {
  675         if ((vp->v_type == VDIR) && (mode & VEXEC)) {
  676             if (coda_nc_lookup(cp, ".", 1, cred)) {
  677                 MARK_INT_SAT(CODA_ACCESS_STATS);
  678                 return(0);                     /* it was in the cache */
  679             }
  680         }
  681     }
  682 
  683     error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, td->td_proc);
  684 
  685     return(error);
  686 }
  687 
  688 int
  689 coda_readlink(struct vop_readlink_args *ap)
  690 {
  691 /* true args */
  692     struct vnode *vp = ap->a_vp;
  693     struct cnode *cp = VTOC(vp);
  694     struct uio *uiop = ap->a_uio;
  695     struct ucred *cred = ap->a_cred;
  696     struct thread *td = ap->a_uio->uio_td;
  697 /* locals */
  698     int error;
  699     char *str;
  700     int len;
  701 
  702     MARK_ENTRY(CODA_READLINK_STATS);
  703 
  704     /* Check for readlink of control object. */
  705     if (IS_CTL_VP(vp)) {
  706         MARK_INT_FAIL(CODA_READLINK_STATS);
  707         return(ENOENT);
  708     }
  709 
  710     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */
  711         uiop->uio_rw = UIO_READ;
  712         error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
  713         if (error)
  714             MARK_INT_FAIL(CODA_READLINK_STATS);
  715         else
  716             MARK_INT_SAT(CODA_READLINK_STATS);
  717         return(error);
  718     }
  719 
  720     error = venus_readlink(vtomi(vp), &cp->c_fid, cred,
  721         td != NULL ? td->td_proc : NULL, &str, &len);
  722 
  723     if (!error) {
  724         uiop->uio_rw = UIO_READ;
  725         error = uiomove(str, len, uiop);
  726 
  727         if (coda_symlink_cache) {
  728             cp->c_symlink = str;
  729             cp->c_symlen = len;
  730             cp->c_flags |= C_SYMLINK;
  731         } else
  732             CODA_FREE(str, len);
  733     }
  734 
  735     CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));)
  736     return(error);
  737 }
  738 
  739 int
  740 coda_fsync(struct vop_fsync_args *ap)
  741 {
  742 /* true args */
  743     struct vnode *vp = ap->a_vp;
  744     struct cnode *cp = VTOC(vp);
  745     struct thread *td = ap->a_td;
  746 /* locals */
  747     struct vnode *convp = cp->c_ovp;
  748     int error;
  749    
  750     MARK_ENTRY(CODA_FSYNC_STATS);
  751 
  752     /* Check for fsync on an unmounting object */
  753     /* The NetBSD kernel, in it's infinite wisdom, can try to fsync
  754      * after an unmount has been initiated.  This is a Bad Thing,
  755      * which we have to avoid.  Not a legitimate failure for stats.
  756      */
  757     if (IS_UNMOUNTING(cp)) {
  758         return(ENODEV);
  759     }
  760 
  761     /* Check for fsync of control object. */
  762     if (IS_CTL_VP(vp)) {
  763         MARK_INT_SAT(CODA_FSYNC_STATS);
  764         return(0);
  765     }
  766 
  767     if (convp)
  768         VOP_FSYNC(convp, MNT_WAIT, td);
  769 
  770     /*
  771      * We see fsyncs with usecount == 1 then usecount == 0.
  772      * For now we ignore them.
  773      */
  774     /*
  775     VI_LOCK(vp);
  776     if (!vp->v_usecount) {
  777         printf("coda_fsync on vnode %p with %d usecount.  c_flags = %x (%x)\n",
  778                 vp, vp->v_usecount, cp->c_flags, cp->c_flags&C_PURGING);
  779     }
  780     VI_UNLOCK(vp);
  781     */
  782 
  783     /*
  784      * We can expect fsync on any vnode at all if venus is pruging it.
  785      * Venus can't very well answer the fsync request, now can it?
  786      * Hopefully, it won't have to, because hopefully, venus preserves
  787      * the (possibly untrue) invariant that it never purges an open
  788      * vnode.  Hopefully.
  789      */
  790     if (cp->c_flags & C_PURGING) {
  791         return(0);
  792     }
  793 
  794     /* needs research */
  795     return 0;
  796     error = venus_fsync(vtomi(vp), &cp->c_fid, td->td_proc);
  797 
  798     CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); );
  799     return(error);
  800 }
  801 
  802 int
  803 coda_inactive(struct vop_inactive_args *ap)
  804 {
  805     /* XXX - at the moment, inactive doesn't look at cred, and doesn't
  806        have a proc pointer.  Oops. */
  807 /* true args */
  808     struct vnode *vp = ap->a_vp;
  809     struct cnode *cp = VTOC(vp);
  810     struct ucred *cred __attribute__((unused)) = NULL;
  811     struct thread *td __attribute__((unused)) = curthread;
  812 /* upcall decl */
  813 /* locals */
  814 
  815     /* We don't need to send inactive to venus - DCS */
  816     MARK_ENTRY(CODA_INACTIVE_STATS);
  817 
  818     if (IS_CTL_VP(vp)) {
  819         MARK_INT_SAT(CODA_INACTIVE_STATS);
  820         return 0;
  821     }
  822 
  823     CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n",
  824                                   coda_f2s(&cp->c_fid), vp->v_mount));)
  825  
  826     /* If an array has been allocated to hold the symlink, deallocate it */
  827     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
  828         if (cp->c_symlink == NULL)
  829             panic("coda_inactive: null symlink pointer in cnode");
  830         
  831         CODA_FREE(cp->c_symlink, cp->c_symlen);
  832         cp->c_flags &= ~C_SYMLINK;
  833         cp->c_symlen = 0;
  834     }
  835 
  836     /* Remove it from the table so it can't be found. */
  837     coda_unsave(cp);
  838     if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) {
  839         myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp));
  840         panic("badness in coda_inactive\n");
  841     }
  842 
  843     if (IS_UNMOUNTING(cp)) {
  844 #ifdef  DEBUG
  845         printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vrefcnt(vp), vp, cp);
  846         if (cp->c_ovp != NULL)
  847             printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
  848                    vrefcnt(vp), vp, cp);
  849 #endif
  850     } else {
  851 #ifdef OLD_DIAGNOSTIC
  852         if (vrefcnt(CTOV(cp))) {
  853             panic("coda_inactive: nonzero reference count");
  854         }
  855         if (cp->c_ovp != NULL) {
  856             panic("coda_inactive:  cp->ovp != NULL");
  857         }
  858 #endif
  859         vgone(vp);
  860     }
  861 
  862     MARK_INT_SAT(CODA_INACTIVE_STATS);
  863     return(0);
  864 }
  865 
  866 /*
  867  * Remote filesystem operations having to do with directory manipulation.
  868  */
  869 
  870 /* 
  871  * It appears that in NetBSD, lookup is supposed to return the vnode locked
  872  */
  873 int
  874 coda_lookup(struct vop_lookup_args *ap)
  875 {
  876 /* true args */
  877     struct vnode *dvp = ap->a_dvp;
  878     struct cnode *dcp = VTOC(dvp);
  879     struct vnode **vpp = ap->a_vpp;
  880     /* 
  881      * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest
  882      * of the string to xlate, and that we must try to get at least
  883      * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth.  I
  884      * could be wrong. 
  885      */
  886     struct componentname  *cnp = ap->a_cnp;
  887     struct ucred *cred = cnp->cn_cred;
  888     struct thread *td = cnp->cn_thread;
  889 /* locals */
  890     struct cnode *cp;
  891     const char *nm = cnp->cn_nameptr;
  892     int len = cnp->cn_namelen;
  893     CodaFid VFid;
  894     int vtype;
  895     int error = 0;
  896 
  897     MARK_ENTRY(CODA_LOOKUP_STATS);
  898 
  899     CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n",
  900                                    nm, coda_f2s(&dcp->c_fid))););
  901 
  902     /* Check for lookup of control object. */
  903     if (IS_CTL_NAME(dvp, nm, len)) {
  904         *vpp = coda_ctlvp;
  905         vref(*vpp);
  906         MARK_INT_SAT(CODA_LOOKUP_STATS);
  907         goto exit;
  908     }
  909 
  910     if (len+1 > CODA_MAXNAMLEN) {
  911         MARK_INT_FAIL(CODA_LOOKUP_STATS);
  912 
  913         CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %s (%s)\n",
  914                                          coda_f2s(&dcp->c_fid), nm)););
  915         *vpp = (struct vnode *)0;
  916         error = EINVAL;
  917         goto exit;
  918     }
  919     /* First try to look the file up in the cfs name cache */
  920     /* lock the parent vnode? */
  921     cp = coda_nc_lookup(dcp, nm, len, cred);
  922     if (cp) {
  923         *vpp = CTOV(cp);
  924         vref(*vpp);
  925         CODADEBUG(CODA_LOOKUP, 
  926                  myprintf(("lookup result %d vpp %p\n",error,*vpp));)
  927     } else {
  928         
  929         /* The name wasn't cached, so we need to contact Venus */
  930         error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc, &VFid, &vtype);
  931         
  932         if (error) {
  933             MARK_INT_FAIL(CODA_LOOKUP_STATS);
  934 
  935             CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %s (%s)%d\n",
  936                                              coda_f2s(&dcp->c_fid), nm, error));)
  937             *vpp = (struct vnode *)0;
  938         } else {
  939             MARK_INT_SAT(CODA_LOOKUP_STATS);
  940             CODADEBUG(CODA_LOOKUP, 
  941                      myprintf(("lookup: %s type %o result %d\n",
  942                                coda_f2s(&VFid), vtype, error)); )
  943             cp = make_coda_node(&VFid, dvp->v_mount, vtype);
  944             *vpp = CTOV(cp);
  945             
  946             /* enter the new vnode in the Name Cache only if the top bit isn't set */
  947             /* And don't enter a new vnode for an invalid one! */
  948             if (!(vtype & CODA_NOCACHE))
  949                 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
  950         }
  951     }
  952 
  953  exit:
  954     /* 
  955      * If we are creating, and this was the last name to be looked up,
  956      * and the error was ENOENT, then there really shouldn't be an
  957      * error and we can make the leaf NULL and return success.  Since
  958      * this is supposed to work under Mach as well as NetBSD, we're
  959      * leaving this fn wrapped.  We also must tell lookup/namei that
  960      * we need to save the last component of the name.  (Create will
  961      * have to free the name buffer later...lucky us...)
  962      */
  963     if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
  964         && (cnp->cn_flags & ISLASTCN)
  965         && (error == ENOENT))
  966     {
  967         error = EJUSTRETURN;
  968         cnp->cn_flags |= SAVENAME;
  969         *ap->a_vpp = NULL;
  970     }
  971 
  972     /* 
  973      * If we are removing, and we are at the last element, and we
  974      * found it, then we need to keep the name around so that the
  975      * removal will go ahead as planned.  Unfortunately, this will
  976      * probably also lock the to-be-removed vnode, which may or may
  977      * not be a good idea.  I'll have to look at the bits of
  978      * coda_remove to make sure.  We'll only save the name if we did in
  979      * fact find the name, otherwise coda_remove won't have a chance
  980      * to free the pathname.  
  981      */
  982     if ((cnp->cn_nameiop == DELETE)
  983         && (cnp->cn_flags & ISLASTCN)
  984         && !error)
  985     {
  986         cnp->cn_flags |= SAVENAME;
  987     }
  988 
  989     /* 
  990      * If the lookup went well, we need to (potentially?) unlock the
  991      * parent, and lock the child.  We are only responsible for
  992      * checking to see if the parent is supposed to be unlocked before
  993      * we return.  We must always lock the child (provided there is
  994      * one, and (the parent isn't locked or it isn't the same as the
  995      * parent.)  Simple, huh?  We can never leave the parent locked unless
  996      * we are ISLASTCN
  997      */
  998     if (!error || (error == EJUSTRETURN)) {
  999         if (cnp->cn_flags & ISDOTDOT) {
 1000             if ((error = VOP_UNLOCK(dvp, 0, td))) {
 1001                 return error; 
 1002             }       
 1003             /* 
 1004              * The parent is unlocked.  As long as there is a child,
 1005              * lock it without bothering to check anything else. 
 1006              */
 1007             if (*ap->a_vpp) {
 1008                 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
 1009                     vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE, td);
 1010                     return (error);
 1011                 }
 1012             }
 1013             vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE, td);
 1014         } else {
 1015             /* The parent is locked, and may be the same as the child */
 1016             if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
 1017                 /* Different, go ahead and lock it. */
 1018                 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
 1019                     return (error);
 1020                 }
 1021             }
 1022         }
 1023     } else {
 1024         /* If the lookup failed, we need to ensure that the leaf is NULL */
 1025         /* Don't change any locking? */
 1026         *ap->a_vpp = NULL;
 1027     }
 1028     return(error);
 1029 }
 1030 
 1031 /*ARGSUSED*/
 1032 int
 1033 coda_create(struct vop_create_args *ap)
 1034 {
 1035 /* true args */
 1036     struct vnode *dvp = ap->a_dvp;
 1037     struct cnode *dcp = VTOC(dvp);
 1038     struct vattr *va = ap->a_vap;
 1039     int exclusive = 1;
 1040     int mode = ap->a_vap->va_mode;
 1041     struct vnode **vpp = ap->a_vpp;
 1042     struct componentname  *cnp = ap->a_cnp;
 1043     struct ucred *cred = cnp->cn_cred;
 1044     struct thread *td = cnp->cn_thread;
 1045 /* locals */
 1046     int error;
 1047     struct cnode *cp;
 1048     const char *nm = cnp->cn_nameptr;
 1049     int len = cnp->cn_namelen;
 1050     CodaFid VFid;
 1051     struct vattr attr;
 1052 
 1053     MARK_ENTRY(CODA_CREATE_STATS);
 1054 
 1055     /* All creates are exclusive XXX */
 1056     /* I'm assuming the 'mode' argument is the file mode bits XXX */
 1057 
 1058     /* Check for create of control object. */
 1059     if (IS_CTL_NAME(dvp, nm, len)) {
 1060         *vpp = (struct vnode *)0;
 1061         MARK_INT_FAIL(CODA_CREATE_STATS);
 1062         return(EACCES);
 1063     }
 1064 
 1065     error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, td->td_proc, &VFid, &attr);
 1066 
 1067     if (!error) {
 1068         
 1069         /* If this is an exclusive create, panic if the file already exists. */
 1070         /* Venus should have detected the file and reported EEXIST. */
 1071 
 1072         if ((exclusive == 1) &&
 1073             (coda_find(&VFid) != NULL))
 1074             panic("cnode existed for newly created file!");
 1075         
 1076         cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
 1077         *vpp = CTOV(cp);
 1078         
 1079         /* Update va to reflect the new attributes. */
 1080         (*va) = attr;
 1081         
 1082         /* Update the attribute cache and mark it as valid */
 1083         if (coda_attr_cache) {
 1084             VTOC(*vpp)->c_vattr = attr;
 1085             VTOC(*vpp)->c_flags |= C_VATTR;       
 1086         }
 1087 
 1088         /* Invalidate the parent's attr cache, the modification time has changed */
 1089         VTOC(dvp)->c_flags &= ~C_VATTR;
 1090         
 1091         /* enter the new vnode in the Name Cache */
 1092         coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
 1093         
 1094         CODADEBUG(CODA_CREATE, 
 1095                   myprintf(("create: %s, result %d\n",
 1096                            coda_f2s(&VFid), error)); )
 1097     } else {
 1098         *vpp = (struct vnode *)0;
 1099         CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));)
 1100     }
 1101 
 1102     if (!error) {
 1103         if (cnp->cn_flags & LOCKLEAF) {
 1104             if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
 1105                 printf("coda_create: ");
 1106                 panic("unlocked parent but couldn't lock child");
 1107             }
 1108         }
 1109 #ifdef OLD_DIAGNOSTIC
 1110         else {
 1111             printf("coda_create: LOCKLEAF not set!\n");
 1112         }
 1113 #endif
 1114     }
 1115     return(error);
 1116 }
 1117 
 1118 int
 1119 coda_remove(struct vop_remove_args *ap)
 1120 {
 1121 /* true args */
 1122     struct vnode *dvp = ap->a_dvp;
 1123     struct cnode *cp = VTOC(dvp);
 1124     struct componentname  *cnp = ap->a_cnp;
 1125     struct ucred *cred = cnp->cn_cred;
 1126     struct thread *td = cnp->cn_thread;
 1127 /* locals */
 1128     int error;
 1129     const char *nm = cnp->cn_nameptr;
 1130     int len = cnp->cn_namelen;
 1131     struct cnode *tp;
 1132 
 1133     MARK_ENTRY(CODA_REMOVE_STATS);
 1134 
 1135     CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n",
 1136                                      nm, coda_f2s(&cp->c_fid))););
 1137     /* Remove the file's entry from the CODA Name Cache */
 1138     /* We're being conservative here, it might be that this person
 1139      * doesn't really have sufficient access to delete the file
 1140      * but we feel zapping the entry won't really hurt anyone -- dcs
 1141      */
 1142     /* I'm gonna go out on a limb here. If a file and a hardlink to it
 1143      * exist, and one is removed, the link count on the other will be
 1144      * off by 1. We could either invalidate the attrs if cached, or
 1145      * fix them. I'll try to fix them. DCS 11/8/94
 1146      */
 1147     tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
 1148     if (tp) {
 1149         if (VALID_VATTR(tp)) {  /* If attrs are cached */
 1150             if (tp->c_vattr.va_nlink > 1) {     /* If it's a hard link */
 1151                 tp->c_vattr.va_nlink--;
 1152             }
 1153         }
 1154         
 1155         coda_nc_zapfile(VTOC(dvp), nm, len); 
 1156         /* No need to flush it if it doesn't exist! */
 1157     }
 1158     /* Invalidate the parent's attr cache, the modification time has changed */
 1159     VTOC(dvp)->c_flags &= ~C_VATTR;
 1160 
 1161     /* Check for remove of control object. */
 1162     if (IS_CTL_NAME(dvp, nm, len)) {
 1163         MARK_INT_FAIL(CODA_REMOVE_STATS);
 1164         return(ENOENT);
 1165     }
 1166 
 1167     error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, td->td_proc);
 1168 
 1169     CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); )
 1170 
 1171     return(error);
 1172 }
 1173 
 1174 int
 1175 coda_link(struct vop_link_args *ap)
 1176 {
 1177 /* true args */
 1178     struct vnode *vp = ap->a_vp;
 1179     struct cnode *cp = VTOC(vp);
 1180     struct vnode *tdvp = ap->a_tdvp;
 1181     struct cnode *tdcp = VTOC(tdvp);
 1182     struct componentname *cnp = ap->a_cnp;
 1183     struct ucred *cred = cnp->cn_cred;
 1184     struct thread *td = cnp->cn_thread;
 1185 /* locals */
 1186     int error;
 1187     const char *nm = cnp->cn_nameptr;
 1188     int len = cnp->cn_namelen;
 1189 
 1190     MARK_ENTRY(CODA_LINK_STATS);
 1191 
 1192     if (codadebug & CODADBGMSK(CODA_LINK)) {
 1193         myprintf(("nb_link:   vp fid: %s\n",
 1194                   coda_f2s(&cp->c_fid)));
 1195         myprintf(("nb_link: tdvp fid: %s)\n",
 1196                   coda_f2s(&tdcp->c_fid)));     
 1197     }
 1198     if (codadebug & CODADBGMSK(CODA_LINK)) {
 1199         myprintf(("link:   vp fid: %s\n",
 1200                   coda_f2s(&cp->c_fid)));
 1201         myprintf(("link: tdvp fid: %s\n",
 1202                   coda_f2s(&tdcp->c_fid)));
 1203     }
 1204 
 1205     /* Check for link to/from control object. */
 1206     if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) {
 1207         MARK_INT_FAIL(CODA_LINK_STATS);
 1208         return(EACCES);
 1209     }
 1210 
 1211     error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, td->td_proc);
 1212 
 1213     /* Invalidate the parent's attr cache, the modification time has changed */
 1214     VTOC(tdvp)->c_flags &= ~C_VATTR;
 1215     VTOC(vp)->c_flags &= ~C_VATTR;
 1216 
 1217     CODADEBUG(CODA_LINK,        myprintf(("in link result %d\n",error)); )
 1218 
 1219     return(error);
 1220 }
 1221 
 1222 int
 1223 coda_rename(struct vop_rename_args *ap)
 1224 {
 1225 /* true args */
 1226     struct vnode *odvp = ap->a_fdvp;
 1227     struct cnode *odcp = VTOC(odvp);
 1228     struct componentname  *fcnp = ap->a_fcnp;
 1229     struct vnode *ndvp = ap->a_tdvp;
 1230     struct cnode *ndcp = VTOC(ndvp);
 1231     struct componentname  *tcnp = ap->a_tcnp;
 1232     struct ucred *cred = fcnp->cn_cred;
 1233     struct thread *td = fcnp->cn_thread;
 1234 /* true args */
 1235     int error;
 1236     const char *fnm = fcnp->cn_nameptr;
 1237     int flen = fcnp->cn_namelen;
 1238     const char *tnm = tcnp->cn_nameptr;
 1239     int tlen = tcnp->cn_namelen;
 1240 
 1241     MARK_ENTRY(CODA_RENAME_STATS);
 1242 
 1243     /* Hmmm.  The vnodes are already looked up.  Perhaps they are locked?
 1244        This could be Bad. XXX */
 1245 #ifdef OLD_DIAGNOSTIC
 1246     if ((fcnp->cn_cred != tcnp->cn_cred)
 1247         || (fcnp->cn_thread != tcnp->cn_thread))
 1248     {
 1249         panic("coda_rename: component names don't agree");
 1250     }
 1251 #endif
 1252 
 1253     /* Check for rename involving control object. */ 
 1254     if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
 1255         MARK_INT_FAIL(CODA_RENAME_STATS);
 1256         return(EACCES);
 1257     }
 1258 
 1259     /* Problem with moving directories -- need to flush entry for .. */
 1260     if (odvp != ndvp) {
 1261         struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred);
 1262         if (ovcp) {
 1263             struct vnode *ovp = CTOV(ovcp);
 1264             if ((ovp) &&
 1265                 (ovp->v_type == VDIR)) /* If it's a directory */
 1266                 coda_nc_zapfile(VTOC(ovp),"..", 2);
 1267         }
 1268     }
 1269 
 1270     /* Remove the entries for both source and target files */
 1271     coda_nc_zapfile(VTOC(odvp), fnm, flen);
 1272     coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
 1273 
 1274     /* Invalidate the parent's attr cache, the modification time has changed */
 1275     VTOC(odvp)->c_flags &= ~C_VATTR;
 1276     VTOC(ndvp)->c_flags &= ~C_VATTR;
 1277 
 1278     if (flen+1 > CODA_MAXNAMLEN) {
 1279         MARK_INT_FAIL(CODA_RENAME_STATS);
 1280         error = EINVAL;
 1281         goto exit;
 1282     }
 1283 
 1284     if (tlen+1 > CODA_MAXNAMLEN) {
 1285         MARK_INT_FAIL(CODA_RENAME_STATS);
 1286         error = EINVAL;
 1287         goto exit;
 1288     }
 1289 
 1290     error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, td->td_proc);
 1291 
 1292  exit:
 1293     CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));)
 1294     /* XXX - do we need to call cache pureg on the moved vnode? */
 1295     cache_purge(ap->a_fvp);
 1296 
 1297     /* It seems to be incumbent on us to drop locks on all four vnodes */
 1298     /* From-vnodes are not locked, only ref'd.  To-vnodes are locked. */
 1299 
 1300     vrele(ap->a_fvp);
 1301     vrele(odvp);
 1302 
 1303     if (ap->a_tvp) {
 1304         if (ap->a_tvp == ndvp) {
 1305             vrele(ap->a_tvp);
 1306         } else {
 1307             vput(ap->a_tvp);
 1308         }
 1309     }
 1310 
 1311     vput(ndvp);
 1312     return(error);
 1313 }
 1314 
 1315 int
 1316 coda_mkdir(struct vop_mkdir_args *ap)
 1317 {
 1318 /* true args */
 1319     struct vnode *dvp = ap->a_dvp;
 1320     struct cnode *dcp = VTOC(dvp);      
 1321     struct componentname  *cnp = ap->a_cnp;
 1322     register struct vattr *va = ap->a_vap;
 1323     struct vnode **vpp = ap->a_vpp;
 1324     struct ucred *cred = cnp->cn_cred;
 1325     struct thread *td = cnp->cn_thread;
 1326 /* locals */
 1327     int error;
 1328     const char *nm = cnp->cn_nameptr;
 1329     int len = cnp->cn_namelen;
 1330     struct cnode *cp;
 1331     CodaFid VFid;
 1332     struct vattr ova;
 1333 
 1334     MARK_ENTRY(CODA_MKDIR_STATS);
 1335 
 1336     /* Check for mkdir of target object. */
 1337     if (IS_CTL_NAME(dvp, nm, len)) {
 1338         *vpp = (struct vnode *)0;
 1339         MARK_INT_FAIL(CODA_MKDIR_STATS);
 1340         return(EACCES);
 1341     }
 1342 
 1343     if (len+1 > CODA_MAXNAMLEN) {
 1344         *vpp = (struct vnode *)0;
 1345         MARK_INT_FAIL(CODA_MKDIR_STATS);
 1346         return(EACCES);
 1347     }
 1348 
 1349     error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, td->td_proc, &VFid, &ova);
 1350 
 1351     if (!error) {
 1352         if (coda_find(&VFid) != NULL)
 1353             panic("cnode existed for newly created directory!");
 1354         
 1355         
 1356         cp =  make_coda_node(&VFid, dvp->v_mount, va->va_type);
 1357         *vpp = CTOV(cp);
 1358         
 1359         /* enter the new vnode in the Name Cache */
 1360         coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
 1361 
 1362         /* as a side effect, enter "." and ".." for the directory */
 1363         coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
 1364         coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
 1365 
 1366         if (coda_attr_cache) {
 1367             VTOC(*vpp)->c_vattr = ova;          /* update the attr cache */
 1368             VTOC(*vpp)->c_flags |= C_VATTR;     /* Valid attributes in cnode */
 1369         }
 1370 
 1371         /* Invalidate the parent's attr cache, the modification time has changed */
 1372         VTOC(dvp)->c_flags &= ~C_VATTR;
 1373         
 1374         CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n",
 1375                                          coda_f2s(&VFid), error)); )
 1376         } else {
 1377         *vpp = (struct vnode *)0;
 1378         CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));)
 1379     }
 1380 
 1381     return(error);
 1382 }
 1383 
 1384 int
 1385 coda_rmdir(struct vop_rmdir_args *ap)
 1386 {
 1387 /* true args */
 1388     struct vnode *dvp = ap->a_dvp;
 1389     struct cnode *dcp = VTOC(dvp);
 1390     struct componentname  *cnp = ap->a_cnp;
 1391     struct ucred *cred = cnp->cn_cred;
 1392     struct thread *td = cnp->cn_thread;
 1393 /* true args */
 1394     int error;
 1395     const char *nm = cnp->cn_nameptr;
 1396     int len = cnp->cn_namelen;
 1397     struct cnode *cp;
 1398    
 1399     MARK_ENTRY(CODA_RMDIR_STATS);
 1400 
 1401     /* Check for rmdir of control object. */
 1402     if (IS_CTL_NAME(dvp, nm, len)) {
 1403         MARK_INT_FAIL(CODA_RMDIR_STATS);
 1404         return(ENOENT);
 1405     }
 1406 
 1407     /* We're being conservative here, it might be that this person
 1408      * doesn't really have sufficient access to delete the file
 1409      * but we feel zapping the entry won't really hurt anyone -- dcs
 1410      */
 1411     /*
 1412      * As a side effect of the rmdir, remove any entries for children of
 1413      * the directory, especially "." and "..".
 1414      */
 1415     cp = coda_nc_lookup(dcp, nm, len, cred);
 1416     if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
 1417 
 1418     /* Remove the file's entry from the CODA Name Cache */
 1419     coda_nc_zapfile(dcp, nm, len);
 1420 
 1421     /* Invalidate the parent's attr cache, the modification time has changed */
 1422     dcp->c_flags &= ~C_VATTR;
 1423 
 1424     error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc);
 1425 
 1426     CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); )
 1427 
 1428     return(error);
 1429 }
 1430 
 1431 int
 1432 coda_symlink(struct vop_symlink_args *ap)
 1433 {
 1434 /* true args */
 1435     struct vnode *tdvp = ap->a_dvp;
 1436     struct cnode *tdcp = VTOC(tdvp);    
 1437     struct componentname *cnp = ap->a_cnp;
 1438     struct vattr *tva = ap->a_vap;
 1439     char *path = ap->a_target;
 1440     struct ucred *cred = cnp->cn_cred;
 1441     struct thread *td = cnp->cn_thread;
 1442     struct vnode **vpp = ap->a_vpp;
 1443 /* locals */
 1444     int error;
 1445     /* 
 1446      * XXX I'm assuming the following things about coda_symlink's
 1447      * arguments: 
 1448      *       t(foo) is the new name/parent/etc being created.
 1449      *       lname is the contents of the new symlink. 
 1450      */
 1451     char *nm = cnp->cn_nameptr;
 1452     int len = cnp->cn_namelen;
 1453     int plen = strlen(path);
 1454 
 1455     /* 
 1456      * Here's the strategy for the moment: perform the symlink, then
 1457      * do a lookup to grab the resulting vnode.  I know this requires
 1458      * two communications with Venus for a new sybolic link, but
 1459      * that's the way the ball bounces.  I don't yet want to change
 1460      * the way the Mach symlink works.  When Mach support is
 1461      * deprecated, we should change symlink so that the common case
 1462      * returns the resultant vnode in a vpp argument.
 1463      */
 1464 
 1465     MARK_ENTRY(CODA_SYMLINK_STATS);
 1466 
 1467     /* Check for symlink of control object. */
 1468     if (IS_CTL_NAME(tdvp, nm, len)) {
 1469         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1470         return(EACCES);
 1471     }
 1472 
 1473     if (plen+1 > CODA_MAXPATHLEN) {
 1474         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1475         return(EINVAL);
 1476     }
 1477 
 1478     if (len+1 > CODA_MAXNAMLEN) {
 1479         MARK_INT_FAIL(CODA_SYMLINK_STATS);
 1480         error = EINVAL;
 1481         goto exit;
 1482     }
 1483 
 1484     error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, td->td_proc);
 1485 
 1486     /* Invalidate the parent's attr cache, the modification time has changed */
 1487     tdcp->c_flags &= ~C_VATTR;
 1488 
 1489     if (error == 0)
 1490         error = VOP_LOOKUP(tdvp, vpp, cnp);
 1491 
 1492  exit:    
 1493     CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); )
 1494     return(error);
 1495 }
 1496 
 1497 /*
 1498  * Read directory entries.
 1499  */
 1500 int
 1501 coda_readdir(struct vop_readdir_args *ap)
 1502 {
 1503 /* true args */
 1504     struct vnode *vp = ap->a_vp;
 1505     struct cnode *cp = VTOC(vp);
 1506     register struct uio *uiop = ap->a_uio;
 1507     struct ucred *cred = ap->a_cred;
 1508     int *eofflag = ap->a_eofflag;
 1509     u_long **cookies = ap->a_cookies;
 1510     int *ncookies = ap->a_ncookies;
 1511     struct thread *td = ap->a_uio->uio_td;
 1512 /* upcall decl */
 1513 /* locals */
 1514     int error = 0;
 1515 
 1516     MARK_ENTRY(CODA_READDIR_STATS);
 1517 
 1518     CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %lld, %d)\n",
 1519                                       (void *)uiop->uio_iov->iov_base,
 1520                                       uiop->uio_resid,
 1521                                       (long long)uiop->uio_offset,
 1522                                       uiop->uio_segflg)); )
 1523         
 1524     /* Check for readdir of control object. */
 1525     if (IS_CTL_VP(vp)) {
 1526         MARK_INT_FAIL(CODA_READDIR_STATS);
 1527         return(ENOENT);
 1528     }
 1529 
 1530     {
 1531         /* If directory is not already open do an "internal open" on it. */
 1532         int opened_internally = 0;
 1533         if (cp->c_ovp == NULL) {
 1534             opened_internally = 1;
 1535             MARK_INT_GEN(CODA_OPEN_STATS);
 1536             error = VOP_OPEN(vp, FREAD, cred, td, -1);
 1537 printf("coda_readdir: Internally Opening %p\n", vp);
 1538             if (error) {
 1539                 printf("coda_readdir: VOP_OPEN on container failed %d\n", error);
 1540                 return (error);
 1541             }
 1542         }
 1543         
 1544         /* Have UFS handle the call. */
 1545         CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = %s, refcnt = %d\n", coda_f2s(&cp->c_fid), vp->v_usecount)); )
 1546         error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies,
 1547                                cookies);
 1548         
 1549         if (error)
 1550             MARK_INT_FAIL(CODA_READDIR_STATS);
 1551         else
 1552             MARK_INT_SAT(CODA_READDIR_STATS);
 1553         
 1554         /* Do an "internal close" if necessary. */ 
 1555         if (opened_internally) {
 1556             MARK_INT_GEN(CODA_CLOSE_STATS);
 1557             (void)VOP_CLOSE(vp, FREAD, cred, td);
 1558         }
 1559     }
 1560 
 1561     return(error);
 1562 }
 1563 
 1564 /*
 1565  * Convert from filesystem blocks to device blocks
 1566  */
 1567 int
 1568 coda_bmap(struct vop_bmap_args *ap)
 1569 {
 1570     /* XXX on the global proc */
 1571 /* true args */
 1572     struct vnode *vp __attribute__((unused)) = ap->a_vp;        /* file's vnode */
 1573     daddr_t bn __attribute__((unused)) = ap->a_bn;      /* fs block number */
 1574     struct bufobj **bop = ap->a_bop;                    /* RETURN bufobj of device */
 1575     daddr_t *bnp __attribute__((unused)) = ap->a_bnp;   /* RETURN device block number */
 1576     struct thread *td __attribute__((unused)) = curthread;
 1577 /* upcall decl */
 1578 /* locals */
 1579 
 1580         int ret = 0;
 1581         struct cnode *cp;
 1582 
 1583         cp = VTOC(vp);
 1584         if (cp->c_ovp) {
 1585                 return EINVAL;
 1586                 ret =  VOP_BMAP(cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb);
 1587 #if     0
 1588                 printf("VOP_BMAP(cp->c_ovp %p, bn %p, bop %p, bnp %lld, ap->a_runp %p, ap->a_runb %p) = %d\n",
 1589                         cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb, ret);
 1590 #endif
 1591                 return ret;
 1592         } else {
 1593 #if     0
 1594                 printf("coda_bmap: no container\n");
 1595 #endif
 1596                 return(EOPNOTSUPP);
 1597         }
 1598 }
 1599 
 1600 int
 1601 coda_reclaim(struct vop_reclaim_args *ap)
 1602 {
 1603 /* true args */
 1604     struct vnode *vp = ap->a_vp;
 1605     struct cnode *cp = VTOC(vp);
 1606 /* upcall decl */
 1607 /* locals */
 1608 
 1609 /*
 1610  * Forced unmount/flush will let vnodes with non zero use be destroyed!
 1611  */
 1612     ENTRY;
 1613 
 1614     if (IS_UNMOUNTING(cp)) {
 1615 #ifdef  DEBUG
 1616         if (VTOC(vp)->c_ovp) {
 1617             if (IS_UNMOUNTING(cp))
 1618                 printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp);
 1619         }
 1620 #endif
 1621     } else {
 1622 #ifdef OLD_DIAGNOSTIC
 1623         if (vrefcnt(vp) != 0) 
 1624             print("coda_reclaim: pushing active %p\n", vp);
 1625         if (VTOC(vp)->c_ovp) {
 1626             panic("coda_reclaim: c_ovp not void");
 1627     }
 1628 #endif
 1629     }   
 1630     cache_purge(vp);
 1631     coda_free(VTOC(vp));
 1632     vp->v_data = NULL;
 1633     vnode_destroy_vobject(vp);
 1634     return (0);
 1635 }
 1636 
 1637 int
 1638 coda_lock(struct vop_lock_args *ap)
 1639 {
 1640 /* true args */
 1641     struct vnode *vp = ap->a_vp;
 1642     struct cnode *cp = VTOC(vp);
 1643 /* upcall decl */
 1644 /* locals */
 1645 
 1646     ENTRY;
 1647 
 1648     if ((ap->a_flags & LK_INTERLOCK) == 0) {
 1649         VI_LOCK(vp);
 1650         ap->a_flags |= LK_INTERLOCK;
 1651     }
 1652 
 1653     if (coda_lockdebug) {
 1654         myprintf(("Attempting lock on %s\n",
 1655                   coda_f2s(&cp->c_fid)));
 1656     }
 1657 
 1658     return (vop_stdlock(ap));
 1659 }
 1660 
 1661 int
 1662 coda_unlock(struct vop_unlock_args *ap)
 1663 {
 1664 /* true args */
 1665     struct vnode *vp = ap->a_vp;
 1666     struct cnode *cp = VTOC(vp);
 1667 /* upcall decl */
 1668 /* locals */
 1669 
 1670     ENTRY;
 1671     if (coda_lockdebug) {
 1672         myprintf(("Attempting unlock on %s\n",
 1673                   coda_f2s(&cp->c_fid)));
 1674     }
 1675 
 1676     return (vop_stdunlock(ap));
 1677 }
 1678 
 1679 int
 1680 coda_islocked(struct vop_islocked_args *ap)
 1681 {
 1682 /* true args */
 1683     ENTRY;
 1684 
 1685     return (vop_stdislocked(ap));
 1686 }
 1687 
 1688 /* How one looks up a vnode given a device/inode pair: */
 1689 int
 1690 coda_grab_vnode(struct cdev *dev, ino_t ino, struct vnode **vpp)
 1691 {
 1692     /* This is like VFS_VGET() or igetinode()! */
 1693     int           error;
 1694     struct mount *mp;
 1695 
 1696     if (!(mp = devtomp(dev))) {
 1697         myprintf(("coda_grab_vnode: devtomp(%#lx) returns NULL\n",
 1698                   (u_long)dev2udev(dev)));
 1699         return(ENXIO);
 1700     }
 1701 
 1702     /* XXX - ensure that nonzero-return means failure */
 1703     error = VFS_VGET(mp,ino,LK_EXCLUSIVE,vpp);
 1704     if (error) {
 1705         myprintf(("coda_grab_vnode: iget/vget(%lx, %lu) returns %p, err %d\n", 
 1706                   (u_long)dev2udev(dev), (u_long)ino, (void *)*vpp, error));
 1707         return(ENOENT);
 1708     }
 1709     return(0);
 1710 }
 1711 
 1712 void
 1713 print_vattr( attr )
 1714         struct vattr *attr;
 1715 {
 1716     char *typestr;
 1717 
 1718     switch (attr->va_type) {
 1719     case VNON:
 1720         typestr = "VNON";
 1721         break;
 1722     case VREG:
 1723         typestr = "VREG";
 1724         break;
 1725     case VDIR:
 1726         typestr = "VDIR";
 1727         break;
 1728     case VBLK:
 1729         typestr = "VBLK";
 1730         break;
 1731     case VCHR:
 1732         typestr = "VCHR";
 1733         break;
 1734     case VLNK:
 1735         typestr = "VLNK";
 1736         break;
 1737     case VSOCK:
 1738         typestr = "VSCK";
 1739         break;
 1740     case VFIFO:
 1741         typestr = "VFFO";
 1742         break;
 1743     case VBAD:
 1744         typestr = "VBAD";
 1745         break;
 1746     default:
 1747         typestr = "????";
 1748         break;
 1749     }
 1750 
 1751 
 1752     myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
 1753               typestr, (int)attr->va_mode, (int)attr->va_uid,
 1754               (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
 1755 
 1756     myprintf(("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
 1757               (int)attr->va_fileid, (int)attr->va_nlink, 
 1758               (int)attr->va_size,
 1759               (int)attr->va_blocksize,(int)attr->va_bytes));
 1760     myprintf(("      gen %ld flags %ld vaflags %d\n",
 1761               attr->va_gen, attr->va_flags, attr->va_vaflags));
 1762     myprintf(("      atime sec %d nsec %d\n",
 1763               (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec));
 1764     myprintf(("      mtime sec %d nsec %d\n",
 1765               (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec));
 1766     myprintf(("      ctime sec %d nsec %d\n",
 1767               (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec));
 1768 }
 1769 
 1770 /* How to print a ucred */
 1771 void
 1772 print_cred(cred)
 1773         struct ucred *cred;
 1774 {
 1775 
 1776         int i;
 1777 
 1778         myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid));
 1779 
 1780         for (i=0; i < cred->cr_ngroups; i++)
 1781                 myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i]));
 1782         myprintf(("\n"));
 1783 
 1784 }
 1785 
 1786 /*
 1787  * Return a vnode for the given fid.
 1788  * If no cnode exists for this fid create one and put it
 1789  * in a table hashed by coda_f2i().  If the cnode for
 1790  * this fid is already in the table return it (ref count is
 1791  * incremented by coda_find.  The cnode will be flushed from the
 1792  * table when coda_inactive calls coda_unsave.
 1793  */
 1794 struct cnode *
 1795 make_coda_node(fid, vfsp, type)
 1796      CodaFid *fid; struct mount *vfsp; short type;
 1797 {
 1798     struct cnode *cp;
 1799     int          err;
 1800 
 1801     if ((cp = coda_find(fid)) == NULL) {
 1802         struct vnode *vp;
 1803         
 1804         cp = coda_alloc();
 1805         cp->c_fid = *fid;
 1806         
 1807         err = getnewvnode("coda", vfsp, &coda_vnodeops, &vp);  
 1808         if (err) {                                                
 1809             panic("coda: getnewvnode returned error %d\n", err);   
 1810         }                                                         
 1811         vp->v_data = cp;                                          
 1812         vp->v_type = type;                                      
 1813         cp->c_vnode = vp;                                         
 1814         coda_save(cp);
 1815         
 1816     } else {
 1817         vref(CTOV(cp));
 1818     }
 1819 
 1820     return cp;
 1821 }
 1822 
 1823 int
 1824 coda_pathconf( struct vop_pathconf_args *ap)
 1825 {
 1826         int error;
 1827         register_t *retval;
 1828 
 1829         retval = ap->a_retval;
 1830         error = 0;
 1831 
 1832         switch (ap->a_name) {
 1833         case _PC_NAME_MAX:
 1834                 *retval = CODA_MAXNAMLEN;
 1835                 break;
 1836         case _PC_PATH_MAX:
 1837                 *retval = CODA_MAXPATHLEN;
 1838                 break;
 1839         default:
 1840                 error = vop_stdpathconf(ap);
 1841                 break;
 1842         }
 1843 
 1844         return (error);
 1845 }

Cache object: ca2e77f7492178dcc57bd63da5294b8e


[ 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.