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