xref: /netbsd/sys/coda/coda_subr.c (revision bf9ec67e)
1 /*	$NetBSD: coda_subr.c,v 1.13 2001/11/12 23:08:57 lukem 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  * 	@(#) coda/coda_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 /* NOTES: rvb
47  * 1.	Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
48  *	 be done before dounmount is called.  Because some of the routines that
49  *	 dounmount calls before coda_unmounted might try to force flushes to venus.
50  *	 The vnode pager does this.
51  * 2.	coda_unmounting marks all cnodes scanning coda_cache.
52  * 3.	cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
53  *	 under the /coda mount point.
54  * 4.	coda_cacheprint (under DEBUG) prints names with vnode/cnode address
55  */
56 
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: coda_subr.c,v 1.13 2001/11/12 23:08:57 lukem Exp $");
59 
60 #ifdef	_LKM
61 #define	NVCODA 4
62 #else
63 #include <vcoda.h>
64 #endif
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
69 #include <sys/proc.h>
70 #include <sys/select.h>
71 #include <sys/mount.h>
72 
73 #include <coda/coda.h>
74 #include <coda/cnode.h>
75 #include <coda/coda_subr.h>
76 #include <coda/coda_namecache.h>
77 
78 int coda_active = 0;
79 int coda_reuse = 0;
80 int coda_new = 0;
81 
82 struct cnode *coda_freelist = NULL;
83 struct cnode *coda_cache[CODA_CACHESIZE];
84 
85 #define coda_hash(fid) \
86     (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
87 
88 #define	CNODE_NEXT(cp)	((cp)->c_next)
89 
90 #define ODD(vnode)        ((vnode) & 0x1)
91 
92 /*
93  * Allocate a cnode.
94  */
95 struct cnode *
96 coda_alloc(void)
97 {
98     struct cnode *cp;
99 
100     if (coda_freelist) {
101 	cp = coda_freelist;
102 	coda_freelist = CNODE_NEXT(cp);
103 	coda_reuse++;
104     }
105     else {
106 	CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
107 	/* NetBSD vnodes don't have any Pager info in them ('cause there are
108 	   no external pagers, duh!) */
109 #define VNODE_VM_INFO_INIT(vp)         /* MT */
110 	VNODE_VM_INFO_INIT(CTOV(cp));
111 	coda_new++;
112     }
113     memset(cp, 0, sizeof (struct cnode));
114 
115     return(cp);
116 }
117 
118 /*
119  * Deallocate a cnode.
120  */
121 void
122 coda_free(cp)
123      struct cnode *cp;
124 {
125 
126     CNODE_NEXT(cp) = coda_freelist;
127     coda_freelist = cp;
128 }
129 
130 /*
131  * Put a cnode in the hash table
132  */
133 void
134 coda_save(cp)
135      struct cnode *cp;
136 {
137 	CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
138 	coda_cache[coda_hash(&cp->c_fid)] = cp;
139 }
140 
141 /*
142  * Remove a cnode from the hash table
143  */
144 void
145 coda_unsave(cp)
146      struct cnode *cp;
147 {
148     struct cnode *ptr;
149     struct cnode *ptrprev = NULL;
150 
151     ptr = coda_cache[coda_hash(&cp->c_fid)];
152     while (ptr != NULL) {
153 	if (ptr == cp) {
154 	    if (ptrprev == NULL) {
155 		coda_cache[coda_hash(&cp->c_fid)]
156 		    = CNODE_NEXT(ptr);
157 	    } else {
158 		CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
159 	    }
160 	    CNODE_NEXT(cp) = (struct cnode *)NULL;
161 
162 	    return;
163 	}
164 	ptrprev = ptr;
165 	ptr = CNODE_NEXT(ptr);
166     }
167 }
168 
169 /*
170  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
171  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
172  */
173 struct cnode *
174 coda_find(fid)
175      ViceFid *fid;
176 {
177     struct cnode *cp;
178 
179     cp = coda_cache[coda_hash(fid)];
180     while (cp) {
181 	if ((cp->c_fid.Vnode == fid->Vnode) &&
182 	    (cp->c_fid.Volume == fid->Volume) &&
183 	    (cp->c_fid.Unique == fid->Unique) &&
184 	    (!IS_UNMOUNTING(cp)))
185 	    {
186 		coda_active++;
187 		return(cp);
188 	    }
189 	cp = CNODE_NEXT(cp);
190     }
191     return(NULL);
192 }
193 
194 /*
195  * coda_kill is called as a side effect to vcopen. To prevent any
196  * cnodes left around from an earlier run of a venus or warden from
197  * causing problems with the new instance, mark any outstanding cnodes
198  * as dying. Future operations on these cnodes should fail (excepting
199  * coda_inactive of course!). Since multiple venii/wardens can be
200  * running, only kill the cnodes for a particular entry in the
201  * coda_mnttbl. -- DCS 12/1/94 */
202 
203 int
204 coda_kill(whoIam, dcstat)
205 	struct mount *whoIam;
206 	enum dc_status dcstat;
207 {
208 	int hash, count = 0;
209 	struct cnode *cp;
210 
211 	/*
212 	 * Algorithm is as follows:
213 	 *     Second, flush whatever vnodes we can from the name cache.
214 	 *
215 	 *     Finally, step through whatever is left and mark them dying.
216 	 *        This prevents any operation at all.
217 
218 	 */
219 
220 	/* This is slightly overkill, but should work. Eventually it'd be
221 	 * nice to only flush those entries from the namecache that
222 	 * reference a vnode in this vfs.  */
223 	coda_nc_flush(dcstat);
224 
225 	for (hash = 0; hash < CODA_CACHESIZE; hash++) {
226 		for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
227 			if (CTOV(cp)->v_mount == whoIam) {
228 #ifdef	DEBUG
229 				printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
230 #endif
231 				count++;
232 				CODADEBUG(CODA_FLUSH,
233 					 myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
234 						   (cp->c_fid).Volume,
235 						   (cp->c_fid).Vnode,
236 						   (cp->c_fid).Unique,
237 						   cp->c_flags,
238 						   CTOV(cp)->v_usecount)); );
239 			}
240 		}
241 	}
242 	return count;
243 }
244 
245 /*
246  * There are two reasons why a cnode may be in use, it may be in the
247  * name cache or it may be executing.
248  */
249 void
250 coda_flush(dcstat)
251 	enum dc_status dcstat;
252 {
253     int hash;
254     struct cnode *cp;
255 
256     coda_clstat.ncalls++;
257     coda_clstat.reqs[CODA_FLUSH]++;
258 
259     coda_nc_flush(dcstat);	    /* flush files from the name cache */
260 
261     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
262 	for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
263 	    if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */
264 		coda_vmflush(cp);
265 	}
266     }
267 }
268 
269 /*
270  * As a debugging measure, print out any cnodes that lived through a
271  * name cache flush.
272  */
273 void
274 coda_testflush(void)
275 {
276     int hash;
277     struct cnode *cp;
278 
279     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
280 	for (cp = coda_cache[hash];
281 	     cp != NULL;
282 	     cp = CNODE_NEXT(cp)) {
283 	    myprintf(("Live cnode fid %lx.%lx.%lx count %d\n",
284 		      (cp->c_fid).Volume,(cp->c_fid).Vnode,
285 		      (cp->c_fid).Unique, CTOV(cp)->v_usecount));
286 	}
287     }
288 }
289 
290 /*
291  *     First, step through all cnodes and mark them unmounting.
292  *         NetBSD kernels may try to fsync them now that venus
293  *         is dead, which would be a bad thing.
294  *
295  */
296 void
297 coda_unmounting(whoIam)
298 	struct mount *whoIam;
299 {
300 	int hash;
301 	struct cnode *cp;
302 
303 	for (hash = 0; hash < CODA_CACHESIZE; hash++) {
304 		for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
305 			if (CTOV(cp)->v_mount == whoIam) {
306 				if (cp->c_flags & (C_LOCKED|C_WANTED)) {
307 					printf("coda_unmounting: Unlocking %p\n", cp);
308 					cp->c_flags &= ~(C_LOCKED|C_WANTED);
309 					wakeup((caddr_t) cp);
310 				}
311 				cp->c_flags |= C_UNMOUNTING;
312 			}
313 		}
314 	}
315 }
316 
317 #ifdef	DEBUG
318 void
319 coda_checkunmounting(mp)
320 	struct mount *mp;
321 {
322 	struct vnode *vp, *nvp;
323 	struct cnode *cp;
324 	int count = 0, bad = 0;
325 loop:
326 	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
327 		if (vp->v_mount != mp)
328 			goto loop;
329 		nvp = vp->v_mntvnodes.le_next;
330 		cp = VTOC(vp);
331 		count++;
332 		if (!(cp->c_flags & C_UNMOUNTING)) {
333 			bad++;
334 			printf("vp %p, cp %p missed\n", vp, cp);
335 			cp->c_flags |= C_UNMOUNTING;
336 		}
337 	}
338 }
339 
340 void
341 coda_cacheprint(whoIam)
342 	struct mount *whoIam;
343 {
344 	int hash;
345 	struct cnode *cp;
346 	int count = 0;
347 
348 	printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
349 	coda_nc_name(VTOC(coda_ctlvp));
350 	printf("\n");
351 
352 	for (hash = 0; hash < CODA_CACHESIZE; hash++) {
353 		for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
354 			if (CTOV(cp)->v_mount == whoIam) {
355 				printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
356 				coda_nc_name(cp);
357 				printf("\n");
358 				count++;
359 			}
360 		}
361 	}
362 	printf("coda_cacheprint: count %d\n", count);
363 }
364 #endif
365 
366 /*
367  * There are 6 cases where invalidations occur. The semantics of each
368  * is listed here.
369  *
370  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
371  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
372  *                  This call is a result of token expiration.
373  *
374  * The next two are the result of callbacks on a file or directory.
375  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
376  *                  Zap all children of this directory from the namecache.
377  * CODA_ZAPFILE   -- flush the attributes for a file.
378  *
379  * The fifth is a result of Venus detecting an inconsistent file.
380  * CODA_PURGEFID  -- flush the attribute for the file
381  *                  If it is a dir (odd vnode), purge its
382  *                  children from the namecache
383  *                  remove the file from the namecache.
384  *
385  * The sixth allows Venus to replace local fids with global ones
386  * during reintegration.
387  *
388  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache
389  */
390 
391 int handleDownCall(opcode, out)
392      int opcode; union outputArgs *out;
393 {
394     int error;
395 
396     /* Handle invalidate requests. */
397     switch (opcode) {
398       case CODA_FLUSH : {
399 
400 	  coda_flush(IS_DOWNCALL);
401 
402 	  CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
403 	      return(0);
404       }
405 
406       case CODA_PURGEUSER : {
407 	  coda_clstat.ncalls++;
408 	  coda_clstat.reqs[CODA_PURGEUSER]++;
409 
410 	  /* XXX - need to prevent fsync's */
411 	  coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
412 	  return(0);
413       }
414 
415       case CODA_ZAPFILE : {
416 	  struct cnode *cp;
417 
418 	  error = 0;
419 	  coda_clstat.ncalls++;
420 	  coda_clstat.reqs[CODA_ZAPFILE]++;
421 
422 	  cp = coda_find(&out->coda_zapfile.CodaFid);
423 	  if (cp != NULL) {
424 	      vref(CTOV(cp));
425 
426 	      cp->c_flags &= ~C_VATTR;
427 	      if (CTOV(cp)->v_flag & VTEXT)
428 		  error = coda_vmflush(cp);
429 	      CODADEBUG(CODA_ZAPFILE, myprintf((
430 		    "zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
431 					      cp->c_fid.Volume,
432 					      cp->c_fid.Vnode,
433 					      cp->c_fid.Unique,
434 					      CTOV(cp)->v_usecount - 1, error)););
435 	      if (CTOV(cp)->v_usecount == 1) {
436 		  cp->c_flags |= C_PURGING;
437 	      }
438 	      vrele(CTOV(cp));
439 	  }
440 
441 	  return(error);
442       }
443 
444       case CODA_ZAPDIR : {
445 	  struct cnode *cp;
446 
447 	  coda_clstat.ncalls++;
448 	  coda_clstat.reqs[CODA_ZAPDIR]++;
449 
450 	  cp = coda_find(&out->coda_zapdir.CodaFid);
451 	  if (cp != NULL) {
452 	      vref(CTOV(cp));
453 
454 	      cp->c_flags &= ~C_VATTR;
455 	      coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);
456 
457 	      CODADEBUG(CODA_ZAPDIR, myprintf((
458 		    "zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",
459 					     cp->c_fid.Volume,
460 					     cp->c_fid.Vnode,
461 					     cp->c_fid.Unique,
462 					     CTOV(cp)->v_usecount - 1)););
463 	      if (CTOV(cp)->v_usecount == 1) {
464 		  cp->c_flags |= C_PURGING;
465 	      }
466 	      vrele(CTOV(cp));
467 	  }
468 
469 	  return(0);
470       }
471 
472       case CODA_PURGEFID : {
473 	  struct cnode *cp;
474 
475 	  error = 0;
476 	  coda_clstat.ncalls++;
477 	  coda_clstat.reqs[CODA_PURGEFID]++;
478 
479 	  cp = coda_find(&out->coda_purgefid.CodaFid);
480 	  if (cp != NULL) {
481 	      vref(CTOV(cp));
482 	      if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
483 		  coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
484 				     IS_DOWNCALL);
485 	      }
486 	      cp->c_flags &= ~C_VATTR;
487 	      coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
488 	      if (!(ODD(out->coda_purgefid.CodaFid.Vnode))
489 		  && (CTOV(cp)->v_flag & VTEXT)) {
490 
491 		  error = coda_vmflush(cp);
492 	      }
493 	      CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
494                                             cp->c_fid.Volume, cp->c_fid.Vnode,
495                                             cp->c_fid.Unique,
496 					    CTOV(cp)->v_usecount - 1, error)););
497 	      if (CTOV(cp)->v_usecount == 1) {
498 		  cp->c_flags |= C_PURGING;
499 	      }
500 	      vrele(CTOV(cp));
501 	  }
502 	  return(error);
503       }
504 
505       case CODA_REPLACE : {
506 	  struct cnode *cp = NULL;
507 
508 	  coda_clstat.ncalls++;
509 	  coda_clstat.reqs[CODA_REPLACE]++;
510 
511 	  cp = coda_find(&out->coda_replace.OldFid);
512 	  if (cp != NULL) {
513 	      /* remove the cnode from the hash table, replace the fid, and reinsert */
514 	      vref(CTOV(cp));
515 	      coda_unsave(cp);
516 	      cp->c_fid = out->coda_replace.NewFid;
517 	      coda_save(cp);
518 
519 	      CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
520 					   out->coda_replace.OldFid.Volume,
521 					   out->coda_replace.OldFid.Vnode,
522 					   out->coda_replace.OldFid.Unique,
523 					   cp->c_fid.Volume, cp->c_fid.Vnode,
524 					   cp->c_fid.Unique, cp));)
525 	      vrele(CTOV(cp));
526 	  }
527 	  return (0);
528       }
529       default:
530       	myprintf(("handleDownCall: unknown opcode %d\n", opcode));
531 	return (EINVAL);
532     }
533 }
534 
535 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
536 
537 int
538 coda_vmflush(cp)
539      struct cnode *cp;
540 {
541     return 0;
542 }
543 
544 
545 /*
546  * kernel-internal debugging switches
547  */
548 
549 void coda_debugon(void)
550 {
551     codadebug = -1;
552     coda_nc_debug = -1;
553     coda_vnop_print_entry = 1;
554     coda_psdev_print_entry = 1;
555     coda_vfsop_print_entry = 1;
556 }
557 
558 void coda_debugoff(void)
559 {
560     codadebug = 0;
561     coda_nc_debug = 0;
562     coda_vnop_print_entry = 0;
563     coda_psdev_print_entry = 0;
564     coda_vfsop_print_entry = 0;
565 }
566 
567 /*
568  * Utilities used by both client and server
569  * Standard levels:
570  * 0) no debugging
571  * 1) hard failures
572  * 2) soft failures
573  * 3) current test software
574  * 4) main procedure entry points
575  * 5) main procedure exit points
576  * 6) utility procedure entry points
577  * 7) utility procedure exit points
578  * 8) obscure procedure entry points
579  * 9) obscure procedure exit points
580  * 10) random stuff
581  * 11) all <= 1
582  * 12) all <= 2
583  * 13) all <= 3
584  * ...
585  */
586