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