Increase the size of the nfsheur hash table as pointed out by
[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.8 2004/03/31 02:34:37 cpressey 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(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(struct cnode *cp)
126 {
127         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
128         coda_cache[coda_hash(&cp->c_fid)] = cp;
129 }
130
131 /*
132  * Remove a cnode from the hash table
133  */
134 void
135 coda_unsave(struct cnode *cp)
136 {
137     struct cnode *ptr;
138     struct cnode *ptrprev = NULL;
139     
140     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
141     while (ptr != NULL) { 
142         if (ptr == cp) { 
143             if (ptrprev == NULL) {
144                 coda_cache[coda_hash(&cp->c_fid)] 
145                     = CNODE_NEXT(ptr);
146             } else {
147                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
148             }
149             CNODE_NEXT(cp) = (struct cnode *)NULL;
150             
151             return; 
152         }       
153         ptrprev = ptr;
154         ptr = CNODE_NEXT(ptr);
155     }   
156 }
157
158 /*
159  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
160  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
161  */
162 struct cnode *
163 coda_find(ViceFid *fid) 
164 {
165     struct cnode *cp;
166
167     cp = coda_cache[coda_hash(fid)];
168     while (cp) {
169         if ((cp->c_fid.Vnode == fid->Vnode) &&
170             (cp->c_fid.Volume == fid->Volume) &&
171             (cp->c_fid.Unique == fid->Unique) &&
172             (!IS_UNMOUNTING(cp)))
173             {
174                 coda_active++;
175                 return(cp); 
176             }               
177         cp = CNODE_NEXT(cp);
178     }
179     return(NULL);
180 }
181
182 /*
183  * coda_kill is called as a side effect to vcopen. To prevent any
184  * cnodes left around from an earlier run of a venus or warden from
185  * causing problems with the new instance, mark any outstanding cnodes
186  * as dying. Future operations on these cnodes should fail (excepting
187  * coda_inactive of course!). Since multiple venii/wardens can be
188  * running, only kill the cnodes for a particular entry in the
189  * coda_mnttbl. -- DCS 12/1/94 */
190
191 int
192 coda_kill(struct mount *whoIam, enum dc_status dcstat)
193 {
194         int hash, count = 0;
195         struct cnode *cp;
196         
197         /* 
198          * Algorithm is as follows: 
199          *     Second, flush whatever vnodes we can from the name cache.
200          * 
201          *     Finally, step through whatever is left and mark them dying.
202          *        This prevents any operation at all.
203          */
204         
205         /* This is slightly overkill, but should work. Eventually it'd be
206          * nice to only flush those entries from the namecache that
207          * reference a vnode in this vfs.  */
208         coda_nc_flush(dcstat);
209         
210         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
211                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
212                         if (CTOV(cp)->v_mount == whoIam) {
213 #ifdef  DEBUG
214                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
215 #endif
216                                 count++;
217                                 CODADEBUG(CODA_FLUSH, 
218                                          myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
219                                                    (cp->c_fid).Volume,
220                                                    (cp->c_fid).Vnode,
221                                                    (cp->c_fid).Unique, 
222                                                    cp->c_flags,
223                                                    CTOV(cp)->v_usecount)); );
224                         }
225                 }
226         }
227         return count;
228 }
229
230 /*
231  * There are two reasons why a cnode may be in use, it may be in the
232  * name cache or it may be executing.  
233  */
234 void
235 coda_flush(enum dc_status dcstat)
236 {
237     int hash;
238     struct cnode *cp;
239     
240     coda_clstat.ncalls++;
241     coda_clstat.reqs[CODA_FLUSH]++;
242     
243     coda_nc_flush(dcstat);          /* flush files from the name cache */
244
245     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
246         for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {  
247             if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */
248                 coda_vmflush(cp);
249         }
250     }
251 }
252
253 /*
254  * As a debugging measure, print out any cnodes that lived through a
255  * name cache flush.  
256  */
257 void
258 coda_testflush(void)
259 {
260     int hash;
261     struct cnode *cp;
262     
263     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
264         for (cp = coda_cache[hash];
265              cp != NULL;
266              cp = CNODE_NEXT(cp)) {  
267             myprintf(("Live cnode fid %lx.%lx.%lx count %d\n",
268                       (cp->c_fid).Volume,(cp->c_fid).Vnode,
269                       (cp->c_fid).Unique, CTOV(cp)->v_usecount));
270         }
271     }
272 }
273
274 /*
275  *     First, step through all cnodes and mark them unmounting.
276  *         NetBSD kernels may try to fsync them now that venus
277  *         is dead, which would be a bad thing.
278  *
279  */
280 void
281 coda_unmounting(struct mount *whoIam)
282 {       
283         int hash;
284         struct cnode *cp;
285
286         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
287                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
288                         if (CTOV(cp)->v_mount == whoIam) {
289                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
290                                         printf("coda_unmounting: Unlocking %p\n", cp);
291                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
292                                         wakeup((caddr_t) cp);
293                                 }
294                                 cp->c_flags |= C_UNMOUNTING;
295                         }
296                 }
297         }
298 }
299
300 #ifdef  DEBUG
301 void
302 coda_checkunmounting(struct mount *mp)
303 {       
304         struct vnode *vp, *nvp;
305         struct cnode *cp;
306         int count = 0, bad = 0;
307         lwkt_tokref ilock;
308
309         lwkt_gettoken(&ilock, &mntvnode_token);
310         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
311                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
312                 if (vp->v_flag & VPLACEMARKER)
313                         continue;
314                 cp = VTOC(vp);
315                 count++;
316                 if (!(cp->c_flags & C_UNMOUNTING)) {
317                         bad++;
318                         printf("vp %p, cp %p missed\n", vp, cp);
319                         cp->c_flags |= C_UNMOUNTING;
320                 }
321         }
322         lwkt_reltoken(&ilock);
323 }
324
325 void
326 coda_cacheprint(struct mount *whoIam)
327 {       
328         int hash;
329         struct cnode *cp;
330         int count = 0;
331
332         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
333         coda_nc_name(VTOC(coda_ctlvp));
334         printf("\n");
335
336         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
337                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
338                         if (CTOV(cp)->v_mount == whoIam) {
339                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
340                                 coda_nc_name(cp);
341                                 printf("\n");
342                                 count++;
343                         }
344                 }
345         }
346         printf("coda_cacheprint: count %d\n", count);
347 }
348 #endif
349
350 /*
351  * There are 6 cases where invalidations occur. The semantics of each
352  * is listed here.
353  *
354  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
355  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
356  *                  This call is a result of token expiration.
357  *
358  * The next two are the result of callbacks on a file or directory.
359  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
360  *                  Zap all children of this directory from the namecache.
361  * CODA_ZAPFILE   -- flush the attributes for a file.
362  *
363  * The fifth is a result of Venus detecting an inconsistent file.
364  * CODA_PURGEFID  -- flush the attribute for the file
365  *                  If it is a dir (odd vnode), purge its 
366  *                  children from the namecache
367  *                  remove the file from the namecache.
368  *
369  * The sixth allows Venus to replace local fids with global ones
370  * during reintegration.
371  *
372  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 
373  */
374
375 int handleDownCall(int opcode, union outputArgs *out)
376 {
377     int error;
378
379     /* Handle invalidate requests. */
380     switch (opcode) {
381       case CODA_FLUSH : {
382
383           coda_flush(IS_DOWNCALL);
384           
385           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
386               return(0);
387       }
388         
389       case CODA_PURGEUSER : {
390           coda_clstat.ncalls++;
391           coda_clstat.reqs[CODA_PURGEUSER]++;
392           
393           /* XXX - need to prevent fsync's */
394           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
395           return(0);
396       }
397         
398       case CODA_ZAPFILE : {
399           struct cnode *cp;
400
401           error = 0;
402           coda_clstat.ncalls++;
403           coda_clstat.reqs[CODA_ZAPFILE]++;
404           
405           cp = coda_find(&out->coda_zapfile.CodaFid);
406           if (cp != NULL) {
407               vref(CTOV(cp));
408               
409               cp->c_flags &= ~C_VATTR;
410               if (CTOV(cp)->v_flag & VTEXT)
411                   error = coda_vmflush(cp);
412               CODADEBUG(CODA_ZAPFILE, 
413                         myprintf(("zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
414                         cp->c_fid.Volume, 
415                             cp->c_fid.Vnode, 
416                             cp->c_fid.Unique, 
417                             CTOV(cp)->v_usecount - 1, error)););
418               if (CTOV(cp)->v_usecount == 1) {
419                   cp->c_flags |= C_PURGING;
420               }
421               vrele(CTOV(cp));
422           }
423           
424           return(error);
425       }
426         
427       case CODA_ZAPDIR : {
428           struct cnode *cp;
429
430           coda_clstat.ncalls++;
431           coda_clstat.reqs[CODA_ZAPDIR]++;
432           
433           cp = coda_find(&out->coda_zapdir.CodaFid);
434           if (cp != NULL) {
435               vref(CTOV(cp));
436               
437               cp->c_flags &= ~C_VATTR;
438               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
439               
440               CODADEBUG(CODA_ZAPDIR, 
441                         myprintf(("zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",
442                                 cp->c_fid.Volume, 
443                                 cp->c_fid.Vnode, 
444                                 cp->c_fid.Unique, 
445                                 CTOV(cp)->v_usecount - 1)););
446               if (CTOV(cp)->v_usecount == 1) {
447                   cp->c_flags |= C_PURGING;
448               }
449               vrele(CTOV(cp));
450           }
451           
452           return(0);
453       }
454         
455       case CODA_PURGEFID : {
456           struct cnode *cp;
457
458           error = 0;
459           coda_clstat.ncalls++;
460           coda_clstat.reqs[CODA_PURGEFID]++;
461
462           cp = coda_find(&out->coda_purgefid.CodaFid);
463           if (cp != NULL) {
464               vref(CTOV(cp));
465               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
466                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
467                                      IS_DOWNCALL);     
468               }
469               cp->c_flags &= ~C_VATTR;
470               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
471               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
472                   && (CTOV(cp)->v_flag & VTEXT)) {
473                   
474                   error = coda_vmflush(cp);
475               }
476               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
477                                             cp->c_fid.Volume, cp->c_fid.Vnode,
478                                             cp->c_fid.Unique, 
479                                             CTOV(cp)->v_usecount - 1, error)););
480               if (CTOV(cp)->v_usecount == 1) {
481                   cp->c_flags |= C_PURGING;
482               }
483               vrele(CTOV(cp));
484           }
485           return(error);
486       }
487
488       case CODA_REPLACE : {
489           struct cnode *cp = NULL;
490
491           coda_clstat.ncalls++;
492           coda_clstat.reqs[CODA_REPLACE]++;
493           
494           cp = coda_find(&out->coda_replace.OldFid);
495           if (cp != NULL) { 
496               /* remove the cnode from the hash table, replace the fid, and reinsert */
497               vref(CTOV(cp));
498               coda_unsave(cp);
499               cp->c_fid = out->coda_replace.NewFid;
500               coda_save(cp);
501
502               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
503                                            out->coda_replace.OldFid.Volume,
504                                            out->coda_replace.OldFid.Vnode,
505                                            out->coda_replace.OldFid.Unique,
506                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
507                                            cp->c_fid.Unique, cp));)
508               vrele(CTOV(cp));
509           }
510           return (0);
511       }
512       default:
513         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
514         return (EINVAL);
515     }
516 }
517
518 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
519
520 int
521 coda_vmflush(struct cnode *cp)
522 {
523     return 0;
524 }
525
526
527 /* 
528  * kernel-internal debugging switches
529  */
530 void coda_debugon(void)
531 {
532     codadebug = -1;
533     coda_nc_debug = -1;
534     coda_vnop_print_entry = 1;
535     coda_psdev_print_entry = 1;
536     coda_vfsop_print_entry = 1;
537 }
538
539 void coda_debugoff(void)
540 {
541     codadebug = 0;
542     coda_nc_debug = 0;
543     coda_vnop_print_entry = 0;
544     coda_psdev_print_entry = 0;
545     coda_vfsop_print_entry = 0;
546 }
547
548 /*
549  * Utilities used by both client and server
550  * Standard levels:
551  * 0) no debugging
552  * 1) hard failures
553  * 2) soft failures
554  * 3) current test software
555  * 4) main procedure entry points
556  * 5) main procedure exit points
557  * 6) utility procedure entry points
558  * 7) utility procedure exit points
559  * 8) obscure procedure entry points
560  * 9) obscure procedure exit points
561  * 10) random stuff
562  * 11) all <= 1
563  * 12) all <= 2
564  * 13) all <= 3
565  * ...
566  */