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

Cache object: 0ebca66e027b65a8561bbc8c9f66d98f


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