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