Merge from vendor branch OPENSSH:
[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.9 2005/04/20 17:01:52 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(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 handleDownCall(int opcode, union outputArgs *out)
374 {
375     int error;
376
377     /* Handle invalidate requests. */
378     switch (opcode) {
379       case CODA_FLUSH : {
380
381           coda_flush(IS_DOWNCALL);
382           
383           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
384               return(0);
385       }
386         
387       case CODA_PURGEUSER : {
388           coda_clstat.ncalls++;
389           coda_clstat.reqs[CODA_PURGEUSER]++;
390           
391           /* XXX - need to prevent fsync's */
392           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
393           return(0);
394       }
395         
396       case CODA_ZAPFILE : {
397           struct cnode *cp;
398
399           error = 0;
400           coda_clstat.ncalls++;
401           coda_clstat.reqs[CODA_ZAPFILE]++;
402           
403           cp = coda_find(&out->coda_zapfile.CodaFid);
404           if (cp != NULL) {
405               vref(CTOV(cp));
406               
407               cp->c_flags &= ~C_VATTR;
408               if (CTOV(cp)->v_flag & VTEXT)
409                   error = coda_vmflush(cp);
410               CODADEBUG(CODA_ZAPFILE, 
411                         myprintf(("zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
412                         cp->c_fid.Volume, 
413                             cp->c_fid.Vnode, 
414                             cp->c_fid.Unique, 
415                             CTOV(cp)->v_usecount - 1, error)););
416               if (CTOV(cp)->v_usecount == 1) {
417                   cp->c_flags |= C_PURGING;
418               }
419               vrele(CTOV(cp));
420           }
421           
422           return(error);
423       }
424         
425       case CODA_ZAPDIR : {
426           struct cnode *cp;
427
428           coda_clstat.ncalls++;
429           coda_clstat.reqs[CODA_ZAPDIR]++;
430           
431           cp = coda_find(&out->coda_zapdir.CodaFid);
432           if (cp != NULL) {
433               vref(CTOV(cp));
434               
435               cp->c_flags &= ~C_VATTR;
436               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);     
437               
438               CODADEBUG(CODA_ZAPDIR, 
439                         myprintf(("zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",
440                                 cp->c_fid.Volume, 
441                                 cp->c_fid.Vnode, 
442                                 cp->c_fid.Unique, 
443                                 CTOV(cp)->v_usecount - 1)););
444               if (CTOV(cp)->v_usecount == 1) {
445                   cp->c_flags |= C_PURGING;
446               }
447               vrele(CTOV(cp));
448           }
449           
450           return(0);
451       }
452         
453       case CODA_PURGEFID : {
454           struct cnode *cp;
455
456           error = 0;
457           coda_clstat.ncalls++;
458           coda_clstat.reqs[CODA_PURGEFID]++;
459
460           cp = coda_find(&out->coda_purgefid.CodaFid);
461           if (cp != NULL) {
462               vref(CTOV(cp));
463               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
464                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
465                                      IS_DOWNCALL);     
466               }
467               cp->c_flags &= ~C_VATTR;
468               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
469               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
470                   && (CTOV(cp)->v_flag & VTEXT)) {
471                   
472                   error = coda_vmflush(cp);
473               }
474               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
475                                             cp->c_fid.Volume, cp->c_fid.Vnode,
476                                             cp->c_fid.Unique, 
477                                             CTOV(cp)->v_usecount - 1, error)););
478               if (CTOV(cp)->v_usecount == 1) {
479                   cp->c_flags |= C_PURGING;
480               }
481               vrele(CTOV(cp));
482           }
483           return(error);
484       }
485
486       case CODA_REPLACE : {
487           struct cnode *cp = NULL;
488
489           coda_clstat.ncalls++;
490           coda_clstat.reqs[CODA_REPLACE]++;
491           
492           cp = coda_find(&out->coda_replace.OldFid);
493           if (cp != NULL) { 
494               /* remove the cnode from the hash table, replace the fid, and reinsert */
495               vref(CTOV(cp));
496               coda_unsave(cp);
497               cp->c_fid = out->coda_replace.NewFid;
498               coda_save(cp);
499
500               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
501                                            out->coda_replace.OldFid.Volume,
502                                            out->coda_replace.OldFid.Vnode,
503                                            out->coda_replace.OldFid.Unique,
504                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
505                                            cp->c_fid.Unique, cp));)
506               vrele(CTOV(cp));
507           }
508           return (0);
509       }
510       default:
511         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
512         return (EINVAL);
513     }
514 }
515
516 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
517
518 int
519 coda_vmflush(struct cnode *cp)
520 {
521     return 0;
522 }
523
524
525 /* 
526  * kernel-internal debugging switches
527  */
528 void coda_debugon(void)
529 {
530     codadebug = -1;
531     coda_nc_debug = -1;
532     coda_vnop_print_entry = 1;
533     coda_psdev_print_entry = 1;
534     coda_vfsop_print_entry = 1;
535 }
536
537 void coda_debugoff(void)
538 {
539     codadebug = 0;
540     coda_nc_debug = 0;
541     coda_vnop_print_entry = 0;
542     coda_psdev_print_entry = 0;
543     coda_vfsop_print_entry = 0;
544 }
545
546 /*
547  * Utilities used by both client and server
548  * Standard levels:
549  * 0) no debugging
550  * 1) hard failures
551  * 2) soft failures
552  * 3) current test software
553  * 4) main procedure entry points
554  * 5) main procedure exit points
555  * 6) utility procedure entry points
556  * 7) utility procedure exit points
557  * 8) obscure procedure entry points
558  * 9) obscure procedure exit points
559  * 10) random stuff
560  * 11) all <= 1
561  * 12) all <= 2
562  * 13) all <= 3
563  * ...
564  */