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