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