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