Initial import from FreeBSD RELENG_4:
[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  * 
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 /* NOTES: rvb
48  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
49  *       be done before dounmount is called.  Because some of the routines that
50  *       dounmount calls before coda_unmounted might try to force flushes to venus.
51  *       The vnode pager does this.
52  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
53  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
54  *       under the /coda mount point.
55  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
56  */
57
58 #include <vcoda.h>
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/proc.h>
63 #include <sys/malloc.h>
64 #include <sys/select.h>
65 #include <sys/mount.h>
66
67 #include <coda/coda.h>
68 #include <coda/cnode.h>
69 #include <coda/coda_subr.h>
70 #include <coda/coda_namecache.h>
71
72 int coda_active = 0;
73 int coda_reuse = 0;
74 int coda_new = 0;
75
76 struct cnode *coda_freelist = NULL;
77 struct cnode *coda_cache[CODA_CACHESIZE];
78
79 #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
80 #define CNODE_NEXT(cp)  ((cp)->c_next)
81 #define ODD(vnode)        ((vnode) & 0x1)
82
83 /*
84  * Allocate a cnode.
85  */
86 struct cnode *
87 coda_alloc(void)
88 {
89     struct cnode *cp;
90
91     if (coda_freelist) {
92         cp = coda_freelist;
93         coda_freelist = CNODE_NEXT(cp);
94         coda_reuse++;
95     }
96     else {
97         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
98         /* NetBSD vnodes don't have any Pager info in them ('cause there are
99            no external pagers, duh!) */
100 #define VNODE_VM_INFO_INIT(vp)         /* MT */
101         VNODE_VM_INFO_INIT(CTOV(cp));
102         coda_new++;
103     }
104     bzero(cp, sizeof (struct cnode));
105
106     return(cp);
107 }
108
109 /*
110  * Deallocate a cnode.
111  */
112 void
113 coda_free(cp)
114      register struct cnode *cp;
115 {
116
117     CNODE_NEXT(cp) = coda_freelist;
118     coda_freelist = cp;
119 }
120
121 /*
122  * Put a cnode in the hash table
123  */
124 void
125 coda_save(cp)
126      struct cnode *cp;
127 {
128         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
129         coda_cache[coda_hash(&cp->c_fid)] = cp;
130 }
131
132 /*
133  * Remove a cnode from the hash table
134  */
135 void
136 coda_unsave(cp)
137      struct cnode *cp;
138 {
139     struct cnode *ptr;
140     struct cnode *ptrprev = NULL;
141     
142     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
143     while (ptr != NULL) { 
144         if (ptr == cp) { 
145             if (ptrprev == NULL) {
146                 coda_cache[coda_hash(&cp->c_fid)] 
147                     = CNODE_NEXT(ptr);
148             } else {
149                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
150             }
151             CNODE_NEXT(cp) = (struct cnode *)NULL;
152             
153             return; 
154         }       
155         ptrprev = ptr;
156         ptr = CNODE_NEXT(ptr);
157     }   
158 }
159
160 /*
161  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
162  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
163  */
164 struct cnode *
165 coda_find(fid) 
166      ViceFid *fid;
167 {
168     struct cnode *cp;
169
170     cp = coda_cache[coda_hash(fid)];
171     while (cp) {
172         if ((cp->c_fid.Vnode == fid->Vnode) &&
173             (cp->c_fid.Volume == fid->Volume) &&
174             (cp->c_fid.Unique == fid->Unique) &&
175             (!IS_UNMOUNTING(cp)))
176             {
177                 coda_active++;
178                 return(cp); 
179             }               
180         cp = CNODE_NEXT(cp);
181     }
182     return(NULL);
183 }
184
185 /*
186  * coda_kill is called as a side effect to vcopen. To prevent any
187  * cnodes left around from an earlier run of a venus or warden from
188  * causing problems with the new instance, mark any outstanding cnodes
189  * as dying. Future operations on these cnodes should fail (excepting
190  * coda_inactive of course!). Since multiple venii/wardens can be
191  * running, only kill the cnodes for a particular entry in the
192  * coda_mnttbl. -- DCS 12/1/94 */
193
194 int
195 coda_kill(whoIam, dcstat)
196         struct mount *whoIam;
197         enum dc_status dcstat;
198 {
199         int hash, count = 0;
200         struct cnode *cp;
201         
202         /* 
203          * Algorithm is as follows: 
204          *     Second, flush whatever vnodes we can from the name cache.
205          * 
206          *     Finally, step through whatever is left and mark them dying.
207          *        This prevents any operation at all.
208          */
209         
210         /* This is slightly overkill, but should work. Eventually it'd be
211          * nice to only flush those entries from the namecache that
212          * reference a vnode in this vfs.  */
213         coda_nc_flush(dcstat);
214         
215         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
216                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
217                         if (CTOV(cp)->v_mount == whoIam) {
218 #ifdef  DEBUG
219                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
220 #endif
221                                 count++;
222                                 CODADEBUG(CODA_FLUSH, 
223                                          myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
224                                                    (cp->c_fid).Volume,
225                                                    (cp->c_fid).Vnode,
226                                                    (cp->c_fid).Unique, 
227                                                    cp->c_flags,
228                                                    CTOV(cp)->v_usecount)); );
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 (!ODD(cp->c_fid.Vnode)) /* 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 %lx.%lx.%lx count %d\n",
274                       (cp->c_fid).Volume,(cp->c_fid).Vnode,
275                       (cp->c_fid).Unique, CTOV(cp)->v_usecount));
276         }
277     }
278 }
279
280 /*
281  *     First, step through all cnodes and mark them unmounting.
282  *         NetBSD kernels may try to fsync them now that venus
283  *         is dead, which would be a bad thing.
284  *
285  */
286 void
287 coda_unmounting(whoIam)
288         struct mount *whoIam;
289 {       
290         int hash;
291         struct cnode *cp;
292
293         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
294                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
295                         if (CTOV(cp)->v_mount == whoIam) {
296                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
297                                         printf("coda_unmounting: Unlocking %p\n", cp);
298                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
299                                         wakeup((caddr_t) cp);
300                                 }
301                                 cp->c_flags |= C_UNMOUNTING;
302                         }
303                 }
304         }
305 }
306
307 #ifdef  DEBUG
308 void
309 coda_checkunmounting(mp)
310         struct mount *mp;
311 {       
312         register struct vnode *vp, *nvp;
313         struct cnode *cp;
314         int count = 0, bad = 0;
315 loop:
316         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
317                 if (vp->v_mount != mp)
318                         goto loop;
319                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
320                 cp = VTOC(vp);
321                 count++;
322                 if (!(cp->c_flags & C_UNMOUNTING)) {
323                         bad++;
324                         printf("vp %p, cp %p missed\n", vp, cp);
325                         cp->c_flags |= C_UNMOUNTING;
326                 }
327         }
328 }
329
330 void
331 coda_cacheprint(whoIam)
332         struct mount *whoIam;
333 {       
334         int hash;
335         struct cnode *cp;
336         int count = 0;
337
338         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
339         coda_nc_name(VTOC(coda_ctlvp));
340         printf("\n");
341
342         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
343                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
344                         if (CTOV(cp)->v_mount == whoIam) {
345                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
346                                 coda_nc_name(cp);
347                                 printf("\n");
348                                 count++;
349                         }
350                 }
351         }
352         printf("coda_cacheprint: count %d\n", count);
353 }
354 #endif
355
356 /*
357  * There are 6 cases where invalidations occur. The semantics of each
358  * is listed here.
359  *
360  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
361  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
362  *                  This call is a result of token expiration.
363  *
364  * The next two are the result of callbacks on a file or directory.
365  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
366  *                  Zap all children of this directory from the namecache.
367  * CODA_ZAPFILE   -- flush the attributes for a file.
368  *
369  * The fifth is a result of Venus detecting an inconsistent file.
370  * CODA_PURGEFID  -- flush the attribute for the file
371  *                  If it is a dir (odd vnode), purge its 
372  *                  children from the namecache
373  *                  remove the file from the namecache.
374  *
375  * The sixth allows Venus to replace local fids with global ones
376  * during reintegration.
377  *
378  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 
379  */
380
381 int handleDownCall(opcode, out)
382      int opcode; union outputArgs *out;
383 {
384     int error;
385
386     /* Handle invalidate requests. */
387     switch (opcode) {
388       case CODA_FLUSH : {
389
390           coda_flush(IS_DOWNCALL);
391           
392           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
393               return(0);
394       }
395         
396       case CODA_PURGEUSER : {
397           coda_clstat.ncalls++;
398           coda_clstat.reqs[CODA_PURGEUSER]++;
399           
400           /* XXX - need to prevent fsync's */
401           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
402           return(0);
403       }
404         
405       case CODA_ZAPFILE : {
406           struct cnode *cp;
407
408           error = 0;
409           coda_clstat.ncalls++;
410           coda_clstat.reqs[CODA_ZAPFILE]++;
411           
412           cp = coda_find(&out->coda_zapfile.CodaFid);
413           if (cp != NULL) {
414               vref(CTOV(cp));
415               
416               cp->c_flags &= ~C_VATTR;
417               if (CTOV(cp)->v_flag & VTEXT)
418                   error = coda_vmflush(cp);
419               CODADEBUG(CODA_ZAPFILE, myprintf(("zapfile: fid = (%lx.%lx.%lx), 
420                                               refcnt = %d, error = %d\n",
421                                               cp->c_fid.Volume, 
422                                               cp->c_fid.Vnode, 
423                                               cp->c_fid.Unique, 
424                                               CTOV(cp)->v_usecount - 1, error)););
425               if (CTOV(cp)->v_usecount == 1) {
426                   cp->c_flags |= C_PURGING;
427               }
428               vrele(CTOV(cp));
429           }
430           
431           return(error);
432       }
433         
434       case CODA_ZAPDIR : {
435           struct cnode *cp;
436
437           coda_clstat.ncalls++;
438           coda_clstat.reqs[CODA_ZAPDIR]++;
439           
440           cp = coda_find(&out->coda_zapdir.CodaFid);
441           if (cp != NULL) {
442               vref(CTOV(cp));
443               
444               cp->c_flags &= ~C_VATTR;
445               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
446               
447               CODADEBUG(CODA_ZAPDIR, myprintf(("zapdir: fid = (%lx.%lx.%lx), 
448                                           refcnt = %d\n",cp->c_fid.Volume, 
449                                              cp->c_fid.Vnode, 
450                                              cp->c_fid.Unique, 
451                                              CTOV(cp)->v_usecount - 1)););
452               if (CTOV(cp)->v_usecount == 1) {
453                   cp->c_flags |= C_PURGING;
454               }
455               vrele(CTOV(cp));
456           }
457           
458           return(0);
459       }
460         
461       case CODA_PURGEFID : {
462           struct cnode *cp;
463
464           error = 0;
465           coda_clstat.ncalls++;
466           coda_clstat.reqs[CODA_PURGEFID]++;
467
468           cp = coda_find(&out->coda_purgefid.CodaFid);
469           if (cp != NULL) {
470               vref(CTOV(cp));
471               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
472                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
473                                      IS_DOWNCALL);     
474               }
475               cp->c_flags &= ~C_VATTR;
476               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
477               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
478                   && (CTOV(cp)->v_flag & VTEXT)) {
479                   
480                   error = coda_vmflush(cp);
481               }
482               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
483                                             cp->c_fid.Volume, cp->c_fid.Vnode,
484                                             cp->c_fid.Unique, 
485                                             CTOV(cp)->v_usecount - 1, error)););
486               if (CTOV(cp)->v_usecount == 1) {
487                   cp->c_flags |= C_PURGING;
488               }
489               vrele(CTOV(cp));
490           }
491           return(error);
492       }
493
494       case CODA_REPLACE : {
495           struct cnode *cp = NULL;
496
497           coda_clstat.ncalls++;
498           coda_clstat.reqs[CODA_REPLACE]++;
499           
500           cp = coda_find(&out->coda_replace.OldFid);
501           if (cp != NULL) { 
502               /* remove the cnode from the hash table, replace the fid, and reinsert */
503               vref(CTOV(cp));
504               coda_unsave(cp);
505               cp->c_fid = out->coda_replace.NewFid;
506               coda_save(cp);
507
508               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
509                                            out->coda_replace.OldFid.Volume,
510                                            out->coda_replace.OldFid.Vnode,
511                                            out->coda_replace.OldFid.Unique,
512                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
513                                            cp->c_fid.Unique, cp));)
514               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  */