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