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