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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5bdd5957d6cc12d042b676f682ad3042


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