proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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.2 2003/06/17 04:28:19 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 <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/coda.h>
69 #include <coda/cnode.h>
70 #include <coda/coda_subr.h>
71 #include <coda/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      register 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         register struct vnode *vp, *nvp;
314         struct cnode *cp;
315         int count = 0, bad = 0;
316 loop:
317         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
318                 if (vp->v_mount != mp)
319                         goto loop;
320                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
321                 cp = VTOC(vp);
322                 count++;
323                 if (!(cp->c_flags & C_UNMOUNTING)) {
324                         bad++;
325                         printf("vp %p, cp %p missed\n", vp, cp);
326                         cp->c_flags |= C_UNMOUNTING;
327                 }
328         }
329 }
330
331 void
332 coda_cacheprint(whoIam)
333         struct mount *whoIam;
334 {       
335         int hash;
336         struct cnode *cp;
337         int count = 0;
338
339         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
340         coda_nc_name(VTOC(coda_ctlvp));
341         printf("\n");
342
343         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
344                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
345                         if (CTOV(cp)->v_mount == whoIam) {
346                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
347                                 coda_nc_name(cp);
348                                 printf("\n");
349                                 count++;
350                         }
351                 }
352         }
353         printf("coda_cacheprint: count %d\n", count);
354 }
355 #endif
356
357 /*
358  * There are 6 cases where invalidations occur. The semantics of each
359  * is listed here.
360  *
361  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
362  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
363  *                  This call is a result of token expiration.
364  *
365  * The next two are the result of callbacks on a file or directory.
366  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
367  *                  Zap all children of this directory from the namecache.
368  * CODA_ZAPFILE   -- flush the attributes for a file.
369  *
370  * The fifth is a result of Venus detecting an inconsistent file.
371  * CODA_PURGEFID  -- flush the attribute for the file
372  *                  If it is a dir (odd vnode), purge its 
373  *                  children from the namecache
374  *                  remove the file from the namecache.
375  *
376  * The sixth allows Venus to replace local fids with global ones
377  * during reintegration.
378  *
379  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 
380  */
381
382 int handleDownCall(opcode, out)
383      int opcode; union outputArgs *out;
384 {
385     int error;
386
387     /* Handle invalidate requests. */
388     switch (opcode) {
389       case CODA_FLUSH : {
390
391           coda_flush(IS_DOWNCALL);
392           
393           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
394               return(0);
395       }
396         
397       case CODA_PURGEUSER : {
398           coda_clstat.ncalls++;
399           coda_clstat.reqs[CODA_PURGEUSER]++;
400           
401           /* XXX - need to prevent fsync's */
402           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
403           return(0);
404       }
405         
406       case CODA_ZAPFILE : {
407           struct cnode *cp;
408
409           error = 0;
410           coda_clstat.ncalls++;
411           coda_clstat.reqs[CODA_ZAPFILE]++;
412           
413           cp = coda_find(&out->coda_zapfile.CodaFid);
414           if (cp != NULL) {
415               vref(CTOV(cp));
416               
417               cp->c_flags &= ~C_VATTR;
418               if (CTOV(cp)->v_flag & VTEXT)
419                   error = coda_vmflush(cp);
420               CODADEBUG(CODA_ZAPFILE, myprintf(("zapfile: fid = (%lx.%lx.%lx), 
421                                               refcnt = %d, error = %d\n",
422                                               cp->c_fid.Volume, 
423                                               cp->c_fid.Vnode, 
424                                               cp->c_fid.Unique, 
425                                               CTOV(cp)->v_usecount - 1, error)););
426               if (CTOV(cp)->v_usecount == 1) {
427                   cp->c_flags |= C_PURGING;
428               }
429               vrele(CTOV(cp));
430           }
431           
432           return(error);
433       }
434         
435       case CODA_ZAPDIR : {
436           struct cnode *cp;
437
438           coda_clstat.ncalls++;
439           coda_clstat.reqs[CODA_ZAPDIR]++;
440           
441           cp = coda_find(&out->coda_zapdir.CodaFid);
442           if (cp != NULL) {
443               vref(CTOV(cp));
444               
445               cp->c_flags &= ~C_VATTR;
446               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
447               
448               CODADEBUG(CODA_ZAPDIR, myprintf(("zapdir: fid = (%lx.%lx.%lx), 
449                                           refcnt = %d\n",cp->c_fid.Volume, 
450                                              cp->c_fid.Vnode, 
451                                              cp->c_fid.Unique, 
452                                              CTOV(cp)->v_usecount - 1)););
453               if (CTOV(cp)->v_usecount == 1) {
454                   cp->c_flags |= C_PURGING;
455               }
456               vrele(CTOV(cp));
457           }
458           
459           return(0);
460       }
461         
462       case CODA_PURGEFID : {
463           struct cnode *cp;
464
465           error = 0;
466           coda_clstat.ncalls++;
467           coda_clstat.reqs[CODA_PURGEFID]++;
468
469           cp = coda_find(&out->coda_purgefid.CodaFid);
470           if (cp != NULL) {
471               vref(CTOV(cp));
472               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
473                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
474                                      IS_DOWNCALL);     
475               }
476               cp->c_flags &= ~C_VATTR;
477               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
478               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
479                   && (CTOV(cp)->v_flag & VTEXT)) {
480                   
481                   error = coda_vmflush(cp);
482               }
483               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
484                                             cp->c_fid.Volume, cp->c_fid.Vnode,
485                                             cp->c_fid.Unique, 
486                                             CTOV(cp)->v_usecount - 1, error)););
487               if (CTOV(cp)->v_usecount == 1) {
488                   cp->c_flags |= C_PURGING;
489               }
490               vrele(CTOV(cp));
491           }
492           return(error);
493       }
494
495       case CODA_REPLACE : {
496           struct cnode *cp = NULL;
497
498           coda_clstat.ncalls++;
499           coda_clstat.reqs[CODA_REPLACE]++;
500           
501           cp = coda_find(&out->coda_replace.OldFid);
502           if (cp != NULL) { 
503               /* remove the cnode from the hash table, replace the fid, and reinsert */
504               vref(CTOV(cp));
505               coda_unsave(cp);
506               cp->c_fid = out->coda_replace.NewFid;
507               coda_save(cp);
508
509               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
510                                            out->coda_replace.OldFid.Volume,
511                                            out->coda_replace.OldFid.Vnode,
512                                            out->coda_replace.OldFid.Unique,
513                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
514                                            cp->c_fid.Unique, cp));)
515               vrele(CTOV(cp));
516           }
517           return (0);
518       }
519       default:
520         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
521         return (EINVAL);
522     }
523 }
524
525 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
526
527 int
528 coda_vmflush(cp)
529      struct cnode *cp;
530 {
531     return 0;
532 }
533
534
535 /* 
536  * kernel-internal debugging switches
537  */
538 void coda_debugon(void)
539 {
540     codadebug = -1;
541     coda_nc_debug = -1;
542     coda_vnop_print_entry = 1;
543     coda_psdev_print_entry = 1;
544     coda_vfsop_print_entry = 1;
545 }
546
547 void coda_debugoff(void)
548 {
549     codadebug = 0;
550     coda_nc_debug = 0;
551     coda_vnop_print_entry = 0;
552     coda_psdev_print_entry = 0;
553     coda_vfsop_print_entry = 0;
554 }
555
556 /*
557  * Utilities used by both client and server
558  * Standard levels:
559  * 0) no debugging
560  * 1) hard failures
561  * 2) soft failures
562  * 3) current test software
563  * 4) main procedure entry points
564  * 5) main procedure exit points
565  * 6) utility procedure entry points
566  * 7) utility procedure exit points
567  * 8) obscure procedure entry points
568  * 9) obscure procedure exit points
569  * 10) random stuff
570  * 11) all <= 1
571  * 12) all <= 2
572  * 13) all <= 3
573  * ...
574  */