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