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