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