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

Cache object: e9571b2113d929fbf090418b4bb2360c


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