]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/coda/coda_subr.c
Fixed warnings for pointer versus int type mismatches. Addresses must
[FreeBSD/FreeBSD.git] / sys / coda / coda_subr.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_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
30  *  $Id: coda_subr.c,v 1.6 1998/09/25 17:38:31 rvb Exp $
31  * 
32   */
33
34 /* 
35  * Mach Operating System
36  * Copyright (c) 1989 Carnegie-Mellon University
37  * All rights reserved.  The CMU software License Agreement specifies
38  * the terms and conditions for use and redistribution.
39  */
40
41 /*
42  * This code was written for the Coda file system at Carnegie Mellon
43  * University.  Contributers include David Steere, James Kistler, and
44  * M. Satyanarayanan.  */
45
46 /*
47  * HISTORY
48  * $Log: coda_subr.c,v $
49  * Revision 1.6  1998/09/25 17:38:31  rvb
50  * Put "stray" printouts under DIAGNOSTIC.  Make everything build
51  * with DEBUG on.  Add support for lkm.  (The macro's don't work
52  * for me; for a good chuckle look at the end of coda_fbsd.c.)
53  *
54  * Revision 1.5  1998/09/13 13:57:59  rvb
55  * Finish conversion of cfs -> coda
56  *
57  * Revision 1.4  1998/09/11 18:50:17  rvb
58  * All the references to cfs, in symbols, structs, and strings
59  * have been changed to coda.  (Same for CFS.)
60  *
61  * Revision 1.2  1998/09/02 19:09:53  rvb
62  * Pass2 complete
63  *
64  * Revision 1.1.1.1  1998/08/29 21:14:52  rvb
65  * Very Preliminary Coda
66  *
67  * Revision 1.11  1998/08/28 18:12:18  rvb
68  * Now it also works on FreeBSD -current.  This code will be
69  * committed to the FreeBSD -current and NetBSD -current
70  * trees.  It will then be tailored to the particular platform
71  * by flushing conditional code.
72  *
73  * Revision 1.10  1998/08/18 17:05:16  rvb
74  * Don't use __RCSID now
75  *
76  * Revision 1.9  1998/08/18 16:31:41  rvb
77  * Sync the code for NetBSD -current; test on 1.3 later
78  *
79  * Revision 1.8  98/01/31  20:53:12  rvb
80  * First version that works on FreeBSD 2.2.5
81  * 
82  * Revision 1.7  98/01/23  11:53:42  rvb
83  * Bring RVB_CODA1_1 to HEAD
84  * 
85  * Revision 1.6.2.3  98/01/23  11:21:05  rvb
86  * Sync with 2.2.5
87  * 
88  * Revision 1.6.2.2  97/12/16  12:40:06  rvb
89  * Sync with 1.3
90  * 
91  * Revision 1.6.2.1  97/12/06  17:41:21  rvb
92  * Sync with peters coda.h
93  * 
94  * Revision 1.6  97/12/05  10:39:17  rvb
95  * Read CHANGES
96  * 
97  * Revision 1.5.4.8  97/11/26  15:28:58  rvb
98  * Cant make downcall pbuf == union cfs_downcalls yet
99  * 
100  * Revision 1.5.4.7  97/11/20  11:46:42  rvb
101  * Capture current cfs_venus
102  * 
103  * Revision 1.5.4.6  97/11/18  10:27:16  rvb
104  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
105  * cfs_nb_foo and cfs_foo are joined
106  * 
107  * Revision 1.5.4.5  97/11/13  22:03:00  rvb
108  * pass2 cfs_NetBSD.h mt
109  * 
110  * Revision 1.5.4.4  97/11/12  12:09:39  rvb
111  * reorg pass1
112  * 
113  * Revision 1.5.4.3  97/11/06  21:02:38  rvb
114  * first pass at ^c ^z
115  * 
116  * Revision 1.5.4.2  97/10/29  16:06:27  rvb
117  * Kill DYING
118  * 
119  * Revision 1.5.4.1  97/10/28 23:10:16  rvb
120  * >64Meg; venus can be killed!
121  *
122  * Revision 1.5  97/08/05  11:08:17  lily
123  * Removed cfsnc_replace, replaced it with a coda_find, unhash, and
124  * rehash.  This fixes a cnode leak and a bug in which the fid is
125  * not actually replaced.  (cfs_namecache.c, cfsnc.h, cfs_subr.c)
126  * 
127  * Revision 1.4  96/12/12  22:10:59  bnoble
128  * Fixed the "downcall invokes venus operation" deadlock in all known cases. 
129  * There may be more
130  * 
131  * Revision 1.3  1996/12/05 16:20:15  bnoble
132  * Minor debugging aids
133  *
134  * Revision 1.2  1996/01/02 16:57:01  bnoble
135  * Added support for Coda MiniCache and raw inode calls (final commit)
136  *
137  * Revision 1.1.2.1  1995/12/20 01:57:27  bnoble
138  * Added CODA-specific files
139  *
140  * Revision 3.1.1.1  1995/03/04  19:07:59  bnoble
141  * Branch for NetBSD port revisions
142  *
143  * Revision 3.1  1995/03/04  19:07:58  bnoble
144  * Bump to major revision 3 to prepare for NetBSD port
145  *
146  * Revision 2.8  1995/03/03  17:00:04  dcs
147  * Fixed kernel bug involving sleep and upcalls. Basically if you killed
148  * a job waiting on venus, the venus upcall queues got trashed. Depending
149  * on luck, you could kill the kernel or not.
150  * (mods to cfs_subr.c and cfs_mach.d)
151  *
152  * Revision 2.7  95/03/02  22:45:21  dcs
153  * Sun4 compatibility
154  * 
155  * Revision 2.6  95/02/17  16:25:17  dcs
156  * These versions represent several changes:
157  * 1. Allow venus to restart even if outstanding references exist.
158  * 2. Have only one ctlvp per client, as opposed to one per mounted cfs device.d
159  * 3. Allow ody_expand to return many members, not just one.
160  * 
161  * Revision 2.5  94/11/09  15:56:26  dcs
162  * Had the thread sleeping on the wrong thing!
163  * 
164  * Revision 2.4  94/10/14  09:57:57  dcs
165  * Made changes 'cause sun4s have braindead compilers
166  * 
167  * Revision 2.3  94/10/12  16:46:26  dcs
168  * Cleaned kernel/venus interface by removing XDR junk, plus
169  * so cleanup to allow this code to be more easily ported.
170  * 
171  * Revision 1.2  92/10/27  17:58:22  lily
172  * merge kernel/latest and alpha/src/cfs
173  * 
174  * Revision 2.4  92/09/30  14:16:26  mja
175  *      Incorporated Dave Steere's fix for the GNU-Emacs bug.
176  *      Also, included his coda_flush routine in place of the former coda_nc_flush.
177  *      [91/02/07            jjk]
178  * 
179  *      Added contributors blurb.
180  *      [90/12/13            jjk]
181  * 
182  *      Hack to allow users to keep coda venus calls uninterruptible. THis
183  *      basically prevents the Gnu-emacs bug from appearing, in which a call
184  *      was being interrupted, and return EINTR, but gnu didn't check for the
185  *      error and figured the file was buggered.
186  *      [90/12/09            dcs]
187  * 
188  * Revision 2.3  90/08/10  10:23:20  mrt
189  *      Removed include of vm/vm_page.h as it no longer exists.
190  *      [90/08/10            mrt]
191  * 
192  * Revision 2.2  90/07/05  11:26:35  mrt
193  *      Initialize name cache on first call to vcopen.
194  *      [90/05/23            dcs]
195  * 
196  *      Created for the Coda File System.
197  *      [90/05/23            dcs]
198  * 
199  * Revision 1.5  90/05/31  17:01:35  dcs
200  * Prepare for merge with facilities kernel.
201  * 
202  * Revision 1.2  90/03/19  15:56:25  dcs
203  * Initialize name cache on first call to vcopen.
204  * 
205  * Revision 1.1  90/03/15  10:43:26  jjk
206  * Initial revision
207  * 
208  */ 
209
210 /* NOTES: rvb
211  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
212  *       be done before dounmount is called.  Because some of the routines that
213  *       dounmount calls before coda_unmounted might try to force flushes to venus.
214  *       The vnode pager does this.
215  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
216  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
217  *       under the /coda mount point.
218  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
219  */
220
221 #ifdef  VFS_LKM
222 #define NVCODA 4
223 #else
224 #include <vcoda.h>
225 #endif
226
227 #include <sys/param.h>
228 #include <sys/systm.h>
229 #include <sys/proc.h>
230 #include <sys/malloc.h>
231 #include <sys/select.h>
232 #include <sys/mount.h>
233
234 #include <coda/coda.h>
235 #include <coda/cnode.h>
236 #include <coda/coda_subr.h>
237 #include <coda/coda_namecache.h>
238
239 int coda_active = 0;
240 int coda_reuse = 0;
241 int coda_new = 0;
242
243 struct cnode *coda_freelist = NULL;
244 struct cnode *coda_cache[CODA_CACHESIZE];
245
246 #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
247 #define CNODE_NEXT(cp)  ((cp)->c_next)
248 #define ODD(vnode)        ((vnode) & 0x1)
249
250 /*
251  * Allocate a cnode.
252  */
253 struct cnode *
254 coda_alloc(void)
255 {
256     struct cnode *cp;
257
258     if (coda_freelist) {
259         cp = coda_freelist;
260         coda_freelist = CNODE_NEXT(cp);
261         coda_reuse++;
262     }
263     else {
264         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
265         /* NetBSD vnodes don't have any Pager info in them ('cause there are
266            no external pagers, duh!) */
267 #define VNODE_VM_INFO_INIT(vp)         /* MT */
268         VNODE_VM_INFO_INIT(CTOV(cp));
269         coda_new++;
270     }
271     bzero(cp, sizeof (struct cnode));
272
273     return(cp);
274 }
275
276 /*
277  * Deallocate a cnode.
278  */
279 void
280 coda_free(cp)
281      register struct cnode *cp;
282 {
283
284     CNODE_NEXT(cp) = coda_freelist;
285     coda_freelist = cp;
286 }
287
288 /*
289  * Put a cnode in the hash table
290  */
291 void
292 coda_save(cp)
293      struct cnode *cp;
294 {
295         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
296         coda_cache[coda_hash(&cp->c_fid)] = cp;
297 }
298
299 /*
300  * Remove a cnode from the hash table
301  */
302 void
303 coda_unsave(cp)
304      struct cnode *cp;
305 {
306     struct cnode *ptr;
307     struct cnode *ptrprev = NULL;
308     
309     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
310     while (ptr != NULL) { 
311         if (ptr == cp) { 
312             if (ptrprev == NULL) {
313                 coda_cache[coda_hash(&cp->c_fid)] 
314                     = CNODE_NEXT(ptr);
315             } else {
316                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
317             }
318             CNODE_NEXT(cp) = (struct cnode *)NULL;
319             
320             return; 
321         }       
322         ptrprev = ptr;
323         ptr = CNODE_NEXT(ptr);
324     }   
325 }
326
327 /*
328  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
329  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
330  */
331 struct cnode *
332 coda_find(fid) 
333      ViceFid *fid;
334 {
335     struct cnode *cp;
336
337     cp = coda_cache[coda_hash(fid)];
338     while (cp) {
339         if ((cp->c_fid.Vnode == fid->Vnode) &&
340             (cp->c_fid.Volume == fid->Volume) &&
341             (cp->c_fid.Unique == fid->Unique) &&
342             (!IS_UNMOUNTING(cp)))
343             {
344                 coda_active++;
345                 return(cp); 
346             }               
347         cp = CNODE_NEXT(cp);
348     }
349     return(NULL);
350 }
351
352 /*
353  * coda_kill is called as a side effect to vcopen. To prevent any
354  * cnodes left around from an earlier run of a venus or warden from
355  * causing problems with the new instance, mark any outstanding cnodes
356  * as dying. Future operations on these cnodes should fail (excepting
357  * coda_inactive of course!). Since multiple venii/wardens can be
358  * running, only kill the cnodes for a particular entry in the
359  * coda_mnttbl. -- DCS 12/1/94 */
360
361 int
362 coda_kill(whoIam, dcstat)
363         struct mount *whoIam;
364         enum dc_status dcstat;
365 {
366         int hash, count = 0;
367         struct cnode *cp;
368         
369         /* 
370          * Algorithm is as follows: 
371          *     Second, flush whatever vnodes we can from the name cache.
372          * 
373          *     Finally, step through whatever is left and mark them dying.
374          *        This prevents any operation at all.
375          */
376         
377         /* This is slightly overkill, but should work. Eventually it'd be
378          * nice to only flush those entries from the namecache that
379          * reference a vnode in this vfs.  */
380         coda_nc_flush(dcstat);
381         
382         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
383                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
384                         if (CTOV(cp)->v_mount == whoIam) {
385 #ifdef  DEBUG
386                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
387 #endif
388                                 count++;
389                                 CODADEBUG(CODA_FLUSH, 
390                                          myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
391                                                    (cp->c_fid).Volume,
392                                                    (cp->c_fid).Vnode,
393                                                    (cp->c_fid).Unique, 
394                                                    cp->c_flags,
395                                                    CTOV(cp)->v_usecount)); );
396                         }
397                 }
398         }
399         return count;
400 }
401
402 /*
403  * There are two reasons why a cnode may be in use, it may be in the
404  * name cache or it may be executing.  
405  */
406 void
407 coda_flush(dcstat)
408         enum dc_status dcstat;
409 {
410     int hash;
411     struct cnode *cp;
412     
413     coda_clstat.ncalls++;
414     coda_clstat.reqs[CODA_FLUSH]++;
415     
416     coda_nc_flush(dcstat);          /* flush files from the name cache */
417
418     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
419         for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {  
420             if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */
421                 coda_vmflush(cp);
422         }
423     }
424 }
425
426 /*
427  * As a debugging measure, print out any cnodes that lived through a
428  * name cache flush.  
429  */
430 void
431 coda_testflush(void)
432 {
433     int hash;
434     struct cnode *cp;
435     
436     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
437         for (cp = coda_cache[hash];
438              cp != NULL;
439              cp = CNODE_NEXT(cp)) {  
440             myprintf(("Live cnode fid %lx.%lx.%lx count %d\n",
441                       (cp->c_fid).Volume,(cp->c_fid).Vnode,
442                       (cp->c_fid).Unique, CTOV(cp)->v_usecount));
443         }
444     }
445 }
446
447 /*
448  *     First, step through all cnodes and mark them unmounting.
449  *         NetBSD kernels may try to fsync them now that venus
450  *         is dead, which would be a bad thing.
451  *
452  */
453 void
454 coda_unmounting(whoIam)
455         struct mount *whoIam;
456 {       
457         int hash;
458         struct cnode *cp;
459
460         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
461                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
462                         if (CTOV(cp)->v_mount == whoIam) {
463                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
464                                         printf("coda_unmounting: Unlocking %p\n", cp);
465                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
466                                         wakeup((caddr_t) cp);
467                                 }
468                                 cp->c_flags |= C_UNMOUNTING;
469                         }
470                 }
471         }
472 }
473
474 #ifdef  DEBUG
475 void
476 coda_checkunmounting(mp)
477         struct mount *mp;
478 {       
479         register struct vnode *vp, *nvp;
480         struct cnode *cp;
481         int count = 0, bad = 0;
482 loop:
483         for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
484                 if (vp->v_mount != mp)
485                         goto loop;
486                 nvp = vp->v_mntvnodes.le_next;
487                 cp = VTOC(vp);
488                 count++;
489                 if (!(cp->c_flags & C_UNMOUNTING)) {
490                         bad++;
491                         printf("vp %p, cp %p missed\n", vp, cp);
492                         cp->c_flags |= C_UNMOUNTING;
493                 }
494         }
495 }
496
497 void
498 coda_cacheprint(whoIam)
499         struct mount *whoIam;
500 {       
501         int hash;
502         struct cnode *cp;
503         int count = 0;
504
505         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
506         coda_nc_name(VTOC(coda_ctlvp));
507         printf("\n");
508
509         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
510                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
511                         if (CTOV(cp)->v_mount == whoIam) {
512                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
513                                 coda_nc_name(cp);
514                                 printf("\n");
515                                 count++;
516                         }
517                 }
518         }
519         printf("coda_cacheprint: count %d\n", count);
520 }
521 #endif
522
523 /*
524  * There are 6 cases where invalidations occur. The semantics of each
525  * is listed here.
526  *
527  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
528  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
529  *                  This call is a result of token expiration.
530  *
531  * The next two are the result of callbacks on a file or directory.
532  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
533  *                  Zap all children of this directory from the namecache.
534  * CODA_ZAPFILE   -- flush the attributes for a file.
535  *
536  * The fifth is a result of Venus detecting an inconsistent file.
537  * CODA_PURGEFID  -- flush the attribute for the file
538  *                  If it is a dir (odd vnode), purge its 
539  *                  children from the namecache
540  *                  remove the file from the namecache.
541  *
542  * The sixth allows Venus to replace local fids with global ones
543  * during reintegration.
544  *
545  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 
546  */
547
548 int handleDownCall(opcode, out)
549      int opcode; union outputArgs *out;
550 {
551     int error;
552
553     /* Handle invalidate requests. */
554     switch (opcode) {
555       case CODA_FLUSH : {
556
557           coda_flush(IS_DOWNCALL);
558           
559           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
560               return(0);
561       }
562         
563       case CODA_PURGEUSER : {
564           coda_clstat.ncalls++;
565           coda_clstat.reqs[CODA_PURGEUSER]++;
566           
567           /* XXX - need to prevent fsync's */
568           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
569           return(0);
570       }
571         
572       case CODA_ZAPFILE : {
573           struct cnode *cp;
574
575           error = 0;
576           coda_clstat.ncalls++;
577           coda_clstat.reqs[CODA_ZAPFILE]++;
578           
579           cp = coda_find(&out->coda_zapfile.CodaFid);
580           if (cp != NULL) {
581               vref(CTOV(cp));
582               
583               cp->c_flags &= ~C_VATTR;
584               if (CTOV(cp)->v_flag & VTEXT)
585                   error = coda_vmflush(cp);
586               CODADEBUG(CODA_ZAPFILE, myprintf(("zapfile: fid = (%lx.%lx.%lx), 
587                                               refcnt = %d, error = %d\n",
588                                               cp->c_fid.Volume, 
589                                               cp->c_fid.Vnode, 
590                                               cp->c_fid.Unique, 
591                                               CTOV(cp)->v_usecount - 1, error)););
592               if (CTOV(cp)->v_usecount == 1) {
593                   cp->c_flags |= C_PURGING;
594               }
595               vrele(CTOV(cp));
596           }
597           
598           return(error);
599       }
600         
601       case CODA_ZAPDIR : {
602           struct cnode *cp;
603
604           coda_clstat.ncalls++;
605           coda_clstat.reqs[CODA_ZAPDIR]++;
606           
607           cp = coda_find(&out->coda_zapdir.CodaFid);
608           if (cp != NULL) {
609               vref(CTOV(cp));
610               
611               cp->c_flags &= ~C_VATTR;
612               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
613               
614               CODADEBUG(CODA_ZAPDIR, myprintf(("zapdir: fid = (%lx.%lx.%lx), 
615                                           refcnt = %d\n",cp->c_fid.Volume, 
616                                              cp->c_fid.Vnode, 
617                                              cp->c_fid.Unique, 
618                                              CTOV(cp)->v_usecount - 1)););
619               if (CTOV(cp)->v_usecount == 1) {
620                   cp->c_flags |= C_PURGING;
621               }
622               vrele(CTOV(cp));
623           }
624           
625           return(0);
626       }
627         
628       case CODA_ZAPVNODE : {
629           coda_clstat.ncalls++;
630           coda_clstat.reqs[CODA_ZAPVNODE]++;
631           
632           myprintf(("CODA_ZAPVNODE: Called, but uniplemented\n"));
633           /*
634            * Not that below we must really translate the returned coda_cred to
635            * a netbsd cred.  This is a bit muddled at present and the cfsnc_zapnode
636            * is further unimplemented, so punt!
637            * I suppose we could use just the uid.
638            */
639           /* coda_nc_zapvnode(&out->coda_zapvnode.VFid, &out->coda_zapvnode.cred,
640                          IS_DOWNCALL); */
641           return(0);
642       } 
643         
644       case CODA_PURGEFID : {
645           struct cnode *cp;
646
647           error = 0;
648           coda_clstat.ncalls++;
649           coda_clstat.reqs[CODA_PURGEFID]++;
650
651           cp = coda_find(&out->coda_purgefid.CodaFid);
652           if (cp != NULL) {
653               vref(CTOV(cp));
654               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
655                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
656                                      IS_DOWNCALL);     
657               }
658               cp->c_flags &= ~C_VATTR;
659               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
660               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
661                   && (CTOV(cp)->v_flag & VTEXT)) {
662                   
663                   error = coda_vmflush(cp);
664               }
665               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
666                                             cp->c_fid.Volume, cp->c_fid.Vnode,
667                                             cp->c_fid.Unique, 
668                                             CTOV(cp)->v_usecount - 1, error)););
669               if (CTOV(cp)->v_usecount == 1) {
670                   cp->c_flags |= C_PURGING;
671               }
672               vrele(CTOV(cp));
673           }
674           return(error);
675       }
676
677       case CODA_REPLACE : {
678           struct cnode *cp = NULL;
679
680           coda_clstat.ncalls++;
681           coda_clstat.reqs[CODA_REPLACE]++;
682           
683           cp = coda_find(&out->coda_replace.OldFid);
684           if (cp != NULL) { 
685               /* remove the cnode from the hash table, replace the fid, and reinsert */
686               vref(CTOV(cp));
687               coda_unsave(cp);
688               cp->c_fid = out->coda_replace.NewFid;
689               coda_save(cp);
690
691               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
692                                            out->coda_replace.OldFid.Volume,
693                                            out->coda_replace.OldFid.Vnode,
694                                            out->coda_replace.OldFid.Unique,
695                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
696                                            cp->c_fid.Unique, cp));)
697               vrele(CTOV(cp));
698           }
699           return (0);
700       }
701       default:
702         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
703         return (EINVAL);
704     }
705 }
706
707 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
708
709 int
710 coda_vmflush(cp)
711      struct cnode *cp;
712 {
713     return 0;
714 }
715
716
717 /* 
718  * kernel-internal debugging switches
719  */
720 void coda_debugon(void)
721 {
722     codadebug = -1;
723     coda_nc_debug = -1;
724     coda_vnop_print_entry = 1;
725     coda_psdev_print_entry = 1;
726     coda_vfsop_print_entry = 1;
727 }
728
729 void coda_debugoff(void)
730 {
731     codadebug = 0;
732     coda_nc_debug = 0;
733     coda_vnop_print_entry = 0;
734     coda_psdev_print_entry = 0;
735     coda_vfsop_print_entry = 0;
736 }
737
738 /*
739  * Utilities used by both client and server
740  * Standard levels:
741  * 0) no debugging
742  * 1) hard failures
743  * 2) soft failures
744  * 3) current test software
745  * 4) main procedure entry points
746  * 5) main procedure exit points
747  * 6) utility procedure entry points
748  * 7) utility procedure exit points
749  * 8) obscure procedure entry points
750  * 9) obscure procedure exit points
751  * 10) random stuff
752  * 11) all <= 1
753  * 12) all <= 2
754  * 13) all <= 3
755  * ...
756  */