Protect the mntvnode scan for coda with the proper token. Since we do not
[dragonfly.git] / sys / vfs / 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  * $FreeBSD: src/sys/coda/coda_subr.c,v 1.11.2.1 2001/10/25 19:18:51 dillon Exp $
31  * $DragonFly: src/sys/vfs/coda/Attic/coda_subr.c,v 1.7 2004/03/29 20:52:17 dillon Exp $
32  * 
33   */
34
35 /* 
36  * Mach Operating System
37  * Copyright (c) 1989 Carnegie-Mellon University
38  * All rights reserved.  The CMU software License Agreement specifies
39  * the terms and conditions for use and redistribution.
40  */
41
42 /*
43  * This code was written for the Coda file system at Carnegie Mellon
44  * University.  Contributers include David Steere, James Kistler, and
45  * M. Satyanarayanan.
46  */
47
48 /* NOTES: rvb
49  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
50  *       be done before dounmount is called.  Because some of the routines that
51  *       dounmount calls before coda_unmounted might try to force flushes to venus.
52  *       The vnode pager does this.
53  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
54  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
55  *       under the /coda mount point.
56  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
57  */
58
59 #include "use_vcoda.h"
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64 #include <sys/malloc.h>
65 #include <sys/select.h>
66 #include <sys/mount.h>
67
68 #include "coda.h"
69 #include "cnode.h"
70 #include "coda_subr.h"
71 #include "coda_namecache.h"
72
73 int coda_active = 0;
74 int coda_reuse = 0;
75 int coda_new = 0;
76
77 struct cnode *coda_freelist = NULL;
78 struct cnode *coda_cache[CODA_CACHESIZE];
79
80 #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
81 #define CNODE_NEXT(cp)  ((cp)->c_next)
82 #define ODD(vnode)        ((vnode) & 0x1)
83
84 /*
85  * Allocate a cnode.
86  */
87 struct cnode *
88 coda_alloc(void)
89 {
90     struct cnode *cp;
91
92     if (coda_freelist) {
93         cp = coda_freelist;
94         coda_freelist = CNODE_NEXT(cp);
95         coda_reuse++;
96     }
97     else {
98         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
99         /* NetBSD vnodes don't have any Pager info in them ('cause there are
100            no external pagers, duh!) */
101 #define VNODE_VM_INFO_INIT(vp)         /* MT */
102         VNODE_VM_INFO_INIT(CTOV(cp));
103         coda_new++;
104     }
105     bzero(cp, sizeof (struct cnode));
106
107     return(cp);
108 }
109
110 /*
111  * Deallocate a cnode.
112  */
113 void
114 coda_free(cp)
115      struct cnode *cp;
116 {
117
118     CNODE_NEXT(cp) = coda_freelist;
119     coda_freelist = cp;
120 }
121
122 /*
123  * Put a cnode in the hash table
124  */
125 void
126 coda_save(cp)
127      struct cnode *cp;
128 {
129         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
130         coda_cache[coda_hash(&cp->c_fid)] = cp;
131 }
132
133 /*
134  * Remove a cnode from the hash table
135  */
136 void
137 coda_unsave(cp)
138      struct cnode *cp;
139 {
140     struct cnode *ptr;
141     struct cnode *ptrprev = NULL;
142     
143     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
144     while (ptr != NULL) { 
145         if (ptr == cp) { 
146             if (ptrprev == NULL) {
147                 coda_cache[coda_hash(&cp->c_fid)] 
148                     = CNODE_NEXT(ptr);
149             } else {
150                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
151             }
152             CNODE_NEXT(cp) = (struct cnode *)NULL;
153             
154             return; 
155         }       
156         ptrprev = ptr;
157         ptr = CNODE_NEXT(ptr);
158     }   
159 }
160
161 /*
162  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
163  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
164  */
165 struct cnode *
166 coda_find(fid) 
167      ViceFid *fid;
168 {
169     struct cnode *cp;
170
171     cp = coda_cache[coda_hash(fid)];
172     while (cp) {
173         if ((cp->c_fid.Vnode == fid->Vnode) &&
174             (cp->c_fid.Volume == fid->Volume) &&
175             (cp->c_fid.Unique == fid->Unique) &&
176             (!IS_UNMOUNTING(cp)))
177             {
178                 coda_active++;
179                 return(cp); 
180             }               
181         cp = CNODE_NEXT(cp);
182     }
183     return(NULL);
184 }
185
186 /*
187  * coda_kill is called as a side effect to vcopen. To prevent any
188  * cnodes left around from an earlier run of a venus or warden from
189  * causing problems with the new instance, mark any outstanding cnodes
190  * as dying. Future operations on these cnodes should fail (excepting
191  * coda_inactive of course!). Since multiple venii/wardens can be
192  * running, only kill the cnodes for a particular entry in the
193  * coda_mnttbl. -- DCS 12/1/94 */
194
195 int
196 coda_kill(whoIam, dcstat)
197         struct mount *whoIam;
198         enum dc_status dcstat;
199 {
200         int hash, count = 0;
201         struct cnode *cp;
202         
203         /* 
204          * Algorithm is as follows: 
205          *     Second, flush whatever vnodes we can from the name cache.
206          * 
207          *     Finally, step through whatever is left and mark them dying.
208          *        This prevents any operation at all.
209          */
210         
211         /* This is slightly overkill, but should work. Eventually it'd be
212          * nice to only flush those entries from the namecache that
213          * reference a vnode in this vfs.  */
214         coda_nc_flush(dcstat);
215         
216         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
217                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
218                         if (CTOV(cp)->v_mount == whoIam) {
219 #ifdef  DEBUG
220                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
221 #endif
222                                 count++;
223                                 CODADEBUG(CODA_FLUSH, 
224                                          myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
225                                                    (cp->c_fid).Volume,
226                                                    (cp->c_fid).Vnode,
227                                                    (cp->c_fid).Unique, 
228                                                    cp->c_flags,
229                                                    CTOV(cp)->v_usecount)); );
230                         }
231                 }
232         }
233         return count;
234 }
235
236 /*
237  * There are two reasons why a cnode may be in use, it may be in the
238  * name cache or it may be executing.  
239  */
240 void
241 coda_flush(dcstat)
242         enum dc_status dcstat;
243 {
244     int hash;
245     struct cnode *cp;
246     
247     coda_clstat.ncalls++;
248     coda_clstat.reqs[CODA_FLUSH]++;
249     
250     coda_nc_flush(dcstat);          /* flush files from the name cache */
251
252     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
253         for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {  
254             if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */
255                 coda_vmflush(cp);
256         }
257     }
258 }
259
260 /*
261  * As a debugging measure, print out any cnodes that lived through a
262  * name cache flush.  
263  */
264 void
265 coda_testflush(void)
266 {
267     int hash;
268     struct cnode *cp;
269     
270     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
271         for (cp = coda_cache[hash];
272              cp != NULL;
273              cp = CNODE_NEXT(cp)) {  
274             myprintf(("Live cnode fid %lx.%lx.%lx count %d\n",
275                       (cp->c_fid).Volume,(cp->c_fid).Vnode,
276                       (cp->c_fid).Unique, CTOV(cp)->v_usecount));
277         }
278     }
279 }
280
281 /*
282  *     First, step through all cnodes and mark them unmounting.
283  *         NetBSD kernels may try to fsync them now that venus
284  *         is dead, which would be a bad thing.
285  *
286  */
287 void
288 coda_unmounting(whoIam)
289         struct mount *whoIam;
290 {       
291         int hash;
292         struct cnode *cp;
293
294         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
295                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
296                         if (CTOV(cp)->v_mount == whoIam) {
297                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
298                                         printf("coda_unmounting: Unlocking %p\n", cp);
299                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
300                                         wakeup((caddr_t) cp);
301                                 }
302                                 cp->c_flags |= C_UNMOUNTING;
303                         }
304                 }
305         }
306 }
307
308 #ifdef  DEBUG
309 void
310 coda_checkunmounting(mp)
311         struct mount *mp;
312 {       
313         struct vnode *vp, *nvp;
314         struct cnode *cp;
315         int count = 0, bad = 0;
316         lwkt_tokref ilock;
317
318         lwkt_gettoken(&ilock, &mntvnode_token);
319         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
320                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
321                 if (vp->v_flag & VPLACEMARKER)
322                         continue;
323                 cp = VTOC(vp);
324                 count++;
325                 if (!(cp->c_flags & C_UNMOUNTING)) {
326                         bad++;
327                         printf("vp %p, cp %p missed\n", vp, cp);
328                         cp->c_flags |= C_UNMOUNTING;
329                 }
330         }
331         lwkt_reltoken(&ilock);
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 ViceFid 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           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
406           return(0);
407       }
408         
409       case CODA_ZAPFILE : {
410           struct cnode *cp;
411
412           error = 0;
413           coda_clstat.ncalls++;
414           coda_clstat.reqs[CODA_ZAPFILE]++;
415           
416           cp = coda_find(&out->coda_zapfile.CodaFid);
417           if (cp != NULL) {
418               vref(CTOV(cp));
419               
420               cp->c_flags &= ~C_VATTR;
421               if (CTOV(cp)->v_flag & VTEXT)
422                   error = coda_vmflush(cp);
423               CODADEBUG(CODA_ZAPFILE, 
424                         myprintf(("zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
425                         cp->c_fid.Volume, 
426                             cp->c_fid.Vnode, 
427                             cp->c_fid.Unique, 
428                             CTOV(cp)->v_usecount - 1, error)););
429               if (CTOV(cp)->v_usecount == 1) {
430                   cp->c_flags |= C_PURGING;
431               }
432               vrele(CTOV(cp));
433           }
434           
435           return(error);
436       }
437         
438       case CODA_ZAPDIR : {
439           struct cnode *cp;
440
441           coda_clstat.ncalls++;
442           coda_clstat.reqs[CODA_ZAPDIR]++;
443           
444           cp = coda_find(&out->coda_zapdir.CodaFid);
445           if (cp != NULL) {
446               vref(CTOV(cp));
447               
448               cp->c_flags &= ~C_VATTR;
449               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
450               
451               CODADEBUG(CODA_ZAPDIR, 
452                         myprintf(("zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",
453                                 cp->c_fid.Volume, 
454                                 cp->c_fid.Vnode, 
455                                 cp->c_fid.Unique, 
456                                 CTOV(cp)->v_usecount - 1)););
457               if (CTOV(cp)->v_usecount == 1) {
458                   cp->c_flags |= C_PURGING;
459               }
460               vrele(CTOV(cp));
461           }
462           
463           return(0);
464       }
465         
466       case CODA_PURGEFID : {
467           struct cnode *cp;
468
469           error = 0;
470           coda_clstat.ncalls++;
471           coda_clstat.reqs[CODA_PURGEFID]++;
472
473           cp = coda_find(&out->coda_purgefid.CodaFid);
474           if (cp != NULL) {
475               vref(CTOV(cp));
476               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
477                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
478                                      IS_DOWNCALL);     
479               }
480               cp->c_flags &= ~C_VATTR;
481               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
482               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
483                   && (CTOV(cp)->v_flag & VTEXT)) {
484                   
485                   error = coda_vmflush(cp);
486               }
487               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
488                                             cp->c_fid.Volume, cp->c_fid.Vnode,
489                                             cp->c_fid.Unique, 
490                                             CTOV(cp)->v_usecount - 1, error)););
491               if (CTOV(cp)->v_usecount == 1) {
492                   cp->c_flags |= C_PURGING;
493               }
494               vrele(CTOV(cp));
495           }
496           return(error);
497       }
498
499       case CODA_REPLACE : {
500           struct cnode *cp = NULL;
501
502           coda_clstat.ncalls++;
503           coda_clstat.reqs[CODA_REPLACE]++;
504           
505           cp = coda_find(&out->coda_replace.OldFid);
506           if (cp != NULL) { 
507               /* remove the cnode from the hash table, replace the fid, and reinsert */
508               vref(CTOV(cp));
509               coda_unsave(cp);
510               cp->c_fid = out->coda_replace.NewFid;
511               coda_save(cp);
512
513               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
514                                            out->coda_replace.OldFid.Volume,
515                                            out->coda_replace.OldFid.Vnode,
516                                            out->coda_replace.OldFid.Unique,
517                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
518                                            cp->c_fid.Unique, cp));)
519               vrele(CTOV(cp));
520           }
521           return (0);
522       }
523       default:
524         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
525         return (EINVAL);
526     }
527 }
528
529 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
530
531 int
532 coda_vmflush(cp)
533      struct cnode *cp;
534 {
535     return 0;
536 }
537
538
539 /* 
540  * kernel-internal debugging switches
541  */
542 void coda_debugon(void)
543 {
544     codadebug = -1;
545     coda_nc_debug = -1;
546     coda_vnop_print_entry = 1;
547     coda_psdev_print_entry = 1;
548     coda_vfsop_print_entry = 1;
549 }
550
551 void coda_debugoff(void)
552 {
553     codadebug = 0;
554     coda_nc_debug = 0;
555     coda_vnop_print_entry = 0;
556     coda_psdev_print_entry = 0;
557     coda_vfsop_print_entry = 0;
558 }
559
560 /*
561  * Utilities used by both client and server
562  * Standard levels:
563  * 0) no debugging
564  * 1) hard failures
565  * 2) soft failures
566  * 3) current test software
567  * 4) main procedure entry points
568  * 5) main procedure exit points
569  * 6) utility procedure entry points
570  * 7) utility procedure exit points
571  * 8) obscure procedure entry points
572  * 9) obscure procedure exit points
573  * 10) random stuff
574  * 11) all <= 1
575  * 12) all <= 2
576  * 13) all <= 3
577  * ...
578  */