]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/coda/coda_subr.c
This commit was generated by cvs2svn to compensate for changes in r126258,
[FreeBSD/FreeBSD.git] / sys / coda / coda_subr.c
1 /*
2  *             Coda: an Experimental Distributed File System
3  *                              Release 3.1
4  * 
5  *           Copyright (c) 1987-1998 Carnegie Mellon University
6  *                          All Rights Reserved
7  * 
8  * Permission  to  use, copy, modify and distribute this software and its
9  * documentation is hereby granted,  provided  that  both  the  copyright
10  * notice  and  this  permission  notice  appear  in  all  copies  of the
11  * software, derivative works or  modified  versions,  and  any  portions
12  * thereof, and that both notices appear in supporting documentation, and
13  * that credit is given to Carnegie Mellon University  in  all  documents
14  * and publicity pertaining to direct or indirect use of this code or its
15  * derivatives.
16  * 
17  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
18  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
19  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
20  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
21  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
22  * ANY DERIVATIVE WORK.
23  * 
24  * Carnegie  Mellon  encourages  users  of  this  software  to return any
25  * improvements or extensions that  they  make,  and  to  grant  Carnegie
26  * Mellon the rights to redistribute these changes without encumbrance.
27  * 
28  *      @(#) src/sys/coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
29  */
30 /* 
31  * Mach Operating System
32  * Copyright (c) 1989 Carnegie-Mellon University
33  * All rights reserved.  The CMU software License Agreement specifies
34  * the terms and conditions for use and redistribution.
35  */
36
37 /*
38  * This code was written for the Coda filesystem at Carnegie Mellon
39  * University.  Contributers include David Steere, James Kistler, and
40  * M. Satyanarayanan.
41  */
42
43 /* NOTES: rvb
44  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
45  *       be done before dounmount is called.  Because some of the routines that
46  *       dounmount calls before coda_unmounted might try to force flushes to venus.
47  *       The vnode pager does this.
48  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
49  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
50  *       under the /coda mount point.
51  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
52  */
53
54 #include <sys/cdefs.h>
55 __FBSDID("$FreeBSD$");
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/lock.h>
60 #include <sys/malloc.h>
61 #include <sys/mutex.h>
62 #include <sys/mount.h>
63
64 #include <coda/coda.h>
65 #include <coda/cnode.h>
66 #include <coda/coda_subr.h>
67 #include <coda/coda_namecache.h>
68
69 int coda_active = 0;
70 int coda_reuse = 0;
71 int coda_new = 0;
72
73 struct cnode *coda_freelist = NULL;
74 struct cnode *coda_cache[CODA_CACHESIZE];
75
76 #define CNODE_NEXT(cp)  ((cp)->c_next)
77
78 #ifdef CODA_COMPAT_5
79 #define coda_hash(fid) \
80     (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
81 #define IS_DIR(cnode)        (cnode.Vnode & 0x1)
82 #else
83 #define coda_hash(fid) (coda_f2i(fid) & (CODA_CACHESIZE-1))
84 #define IS_DIR(cnode)        (cnode.opaque[2] & 0x1)
85 #endif
86
87 /*
88  * Allocate a cnode.
89  */
90 struct cnode *
91 coda_alloc(void)
92 {
93     struct cnode *cp;
94
95     if (coda_freelist) {
96         cp = coda_freelist;
97         coda_freelist = CNODE_NEXT(cp);
98         coda_reuse++;
99     }
100     else {
101         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
102         /* NetBSD vnodes don't have any Pager info in them ('cause there are
103            no external pagers, duh!) */
104 #define VNODE_VM_INFO_INIT(vp)         /* MT */
105         VNODE_VM_INFO_INIT(CTOV(cp));
106         coda_new++;
107     }
108     bzero(cp, sizeof (struct cnode));
109
110     return(cp);
111 }
112
113 /*
114  * Deallocate a cnode.
115  */
116 void
117 coda_free(cp)
118      register struct cnode *cp;
119 {
120
121     CNODE_NEXT(cp) = coda_freelist;
122     coda_freelist = cp;
123 }
124
125 /*
126  * Put a cnode in the hash table
127  */
128 void
129 coda_save(cp)
130      struct cnode *cp;
131 {
132         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
133         coda_cache[coda_hash(&cp->c_fid)] = cp;
134 }
135
136 /*
137  * Remove a cnode from the hash table
138  */
139 void
140 coda_unsave(cp)
141      struct cnode *cp;
142 {
143     struct cnode *ptr;
144     struct cnode *ptrprev = NULL;
145     
146     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
147     while (ptr != NULL) { 
148         if (ptr == cp) { 
149             if (ptrprev == NULL) {
150                 coda_cache[coda_hash(&cp->c_fid)] 
151                     = CNODE_NEXT(ptr);
152             } else {
153                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
154             }
155             CNODE_NEXT(cp) = (struct cnode *)NULL;
156             
157             return; 
158         }       
159         ptrprev = ptr;
160         ptr = CNODE_NEXT(ptr);
161     }   
162 }
163
164 /*
165  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
166  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
167  */
168 struct cnode *
169 coda_find(fid) 
170      CodaFid *fid;
171 {
172     struct cnode *cp;
173
174     cp = coda_cache[coda_hash(fid)];
175     while (cp) {
176             if (coda_fid_eq(&(cp->c_fid), fid) &&
177             (!IS_UNMOUNTING(cp)))
178             {
179                 coda_active++;
180                 return(cp); 
181             }               
182         cp = CNODE_NEXT(cp);
183     }
184     return(NULL);
185 }
186
187 /*
188  * coda_kill is called as a side effect to vcopen. To prevent any
189  * cnodes left around from an earlier run of a venus or warden from
190  * causing problems with the new instance, mark any outstanding cnodes
191  * as dying. Future operations on these cnodes should fail (excepting
192  * coda_inactive of course!). Since multiple venii/wardens can be
193  * running, only kill the cnodes for a particular entry in the
194  * coda_mnttbl. -- DCS 12/1/94 */
195
196 int
197 coda_kill(whoIam, dcstat)
198         struct mount *whoIam;
199         enum dc_status dcstat;
200 {
201         int hash, count = 0;
202         struct cnode *cp;
203         
204         /* 
205          * Algorithm is as follows: 
206          *     Second, flush whatever vnodes we can from the name cache.
207          * 
208          *     Finally, step through whatever is left and mark them dying.
209          *        This prevents any operation at all.
210          */
211         
212         /* This is slightly overkill, but should work. Eventually it'd be
213          * nice to only flush those entries from the namecache that
214          * reference a vnode in this vfs.  */
215         coda_nc_flush(dcstat);
216         
217         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
218                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
219                         if (CTOV(cp)->v_mount == whoIam) {
220 #ifdef  DEBUG
221                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
222 #endif
223                                 count++;
224                                 CODADEBUG(CODA_FLUSH, 
225                                           myprintf(("Live cnode fid %s flags %d count %d\n",
226                                                     coda_f2s(&cp->c_fid),
227                                                     cp->c_flags,
228                                                     vrefcnt(CTOV(cp)))); );
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 (!IS_DIR(cp->c_fid)) /* 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 %s count %d\n",
274                       coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount));
275         }
276     }
277 }
278
279 /*
280  *     First, step through all cnodes and mark them unmounting.
281  *         NetBSD kernels may try to fsync them now that venus
282  *         is dead, which would be a bad thing.
283  *
284  */
285 void
286 coda_unmounting(whoIam)
287         struct mount *whoIam;
288 {       
289         int hash;
290         struct cnode *cp;
291
292         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
293                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
294                         if (CTOV(cp)->v_mount == whoIam) {
295                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
296                                         printf("coda_unmounting: Unlocking %p\n", cp);
297                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
298                                         wakeup((caddr_t) cp);
299                                 }
300                                 cp->c_flags |= C_UNMOUNTING;
301                         }
302                 }
303         }
304 }
305
306 #ifdef  DEBUG
307 void
308 coda_checkunmounting(mp)
309         struct mount *mp;
310 {
311         register struct vnode *vp, *nvp;
312         struct cnode *cp;
313         int count = 0, bad = 0;
314
315         MNT_ILOCK(mp);
316         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
317                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
318                 if (vp->v_mount != mp)
319                         continue;
320                 VI_LOCK(vp);
321                 if (vp->v_iflag & VI_XLOCK) {
322                         VI_UNLOCK(vp);
323                         continue;
324                 }
325                 cp = VTOC(vp);
326                 count++;
327                 if (!(cp->c_flags & C_UNMOUNTING)) {
328                         bad++;
329                         printf("vp %p, cp %p missed\n", vp, cp);
330                         cp->c_flags |= C_UNMOUNTING;
331                 }
332                 VI_UNLOCK(vp);
333         }
334         MNT_IUNLOCK(mp);
335 }
336
337 void
338 coda_cacheprint(whoIam)
339         struct mount *whoIam;
340 {       
341         int hash;
342         struct cnode *cp;
343         int count = 0;
344
345         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
346         coda_nc_name(VTOC(coda_ctlvp));
347         printf("\n");
348
349         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
350                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
351                         if (CTOV(cp)->v_mount == whoIam) {
352                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
353                                 coda_nc_name(cp);
354                                 printf("\n");
355                                 count++;
356                         }
357                 }
358         }
359         printf("coda_cacheprint: count %d\n", count);
360 }
361 #endif
362
363 /*
364  * There are 6 cases where invalidations occur. The semantics of each
365  * is listed here.
366  *
367  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
368  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
369  *                  This call is a result of token expiration.
370  *
371  * The next two are the result of callbacks on a file or directory.
372  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
373  *                  Zap all children of this directory from the namecache.
374  * CODA_ZAPFILE   -- flush the attributes for a file.
375  *
376  * The fifth is a result of Venus detecting an inconsistent file.
377  * CODA_PURGEFID  -- flush the attribute for the file
378  *                  If it is a dir (odd vnode), purge its 
379  *                  children from the namecache
380  *                  remove the file from the namecache.
381  *
382  * The sixth allows Venus to replace local fids with global ones
383  * during reintegration.
384  *
385  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache 
386  */
387
388 int handleDownCall(opcode, out)
389      int opcode; union outputArgs *out;
390 {
391     int error;
392
393     /* Handle invalidate requests. */
394     switch (opcode) {
395       case CODA_FLUSH : {
396
397           coda_flush(IS_DOWNCALL);
398           
399           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
400               return(0);
401       }
402         
403       case CODA_PURGEUSER : {
404           coda_clstat.ncalls++;
405           coda_clstat.reqs[CODA_PURGEUSER]++;
406           
407           /* XXX - need to prevent fsync's */
408 #ifdef CODA_COMPAT_5
409           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
410 #else
411           coda_nc_purge_user(out->coda_purgeuser.uid, IS_DOWNCALL);
412 #endif
413           return(0);
414       }
415         
416       case CODA_ZAPFILE : {
417           struct cnode *cp;
418
419           error = 0;
420           coda_clstat.ncalls++;
421           coda_clstat.reqs[CODA_ZAPFILE]++;
422           
423           cp = coda_find(&out->coda_zapfile.Fid);
424           if (cp != NULL) {
425               vref(CTOV(cp));
426               
427               cp->c_flags &= ~C_VATTR;
428               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
429               if (CTOV(cp)->v_vflag & VV_TEXT)
430                   error = coda_vmflush(cp);
431               CODADEBUG(CODA_ZAPFILE, 
432                         myprintf(("zapfile: fid = %s, refcnt = %d, error = %d\n",
433                                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
434     if (vrefcnt(CTOV(cp)) == 1) {
435                   cp->c_flags |= C_PURGING;
436               }
437               vrele(CTOV(cp));
438           }
439           
440           return(error);
441       }
442         
443       case CODA_ZAPDIR : {
444           struct cnode *cp;
445
446           coda_clstat.ncalls++;
447           coda_clstat.reqs[CODA_ZAPDIR]++;
448           
449           cp = coda_find(&out->coda_zapdir.Fid);
450           if (cp != NULL) {
451               vref(CTOV(cp));
452               
453               cp->c_flags &= ~C_VATTR;
454               coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL);
455
456               CODADEBUG(CODA_ZAPDIR, myprintf((
457                   "zapdir: fid = %s, refcnt = %d\n",
458                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1)););
459               if (vrefcnt(CTOV(cp)) == 1) {
460                   cp->c_flags |= C_PURGING;
461               }
462               vrele(CTOV(cp));
463           }
464           
465           return(0);
466       }
467         
468       case CODA_PURGEFID : {
469           struct cnode *cp;
470
471           error = 0;
472           coda_clstat.ncalls++;
473           coda_clstat.reqs[CODA_PURGEFID]++;
474
475           cp = coda_find(&out->coda_purgefid.Fid);
476           if (cp != NULL) {
477               vref(CTOV(cp));
478               if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */
479                       coda_nc_zapParentfid(&out->coda_purgefid.Fid,IS_DOWNCALL);     
480               }
481               cp->c_flags &= ~C_VATTR;
482               coda_nc_zapfid(&out->coda_purgefid.Fid, IS_DOWNCALL);
483               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
484               if (!(IS_DIR(out->coda_purgefid.Fid)) 
485                   && (CTOV(cp)->v_vflag & VV_TEXT)) {
486                   
487                   error = coda_vmflush(cp);
488               }
489               CODADEBUG(CODA_PURGEFID, myprintf((
490                          "purgefid: fid = %s, refcnt = %d, error = %d\n",
491                          coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
492               if (vrefcnt(CTOV(cp)) == 1) {
493                   cp->c_flags |= C_PURGING;
494               }
495               vrele(CTOV(cp));
496           }
497           return(error);
498       }
499
500       case CODA_REPLACE : {
501           struct cnode *cp = NULL;
502
503           coda_clstat.ncalls++;
504           coda_clstat.reqs[CODA_REPLACE]++;
505           
506           cp = coda_find(&out->coda_replace.OldFid);
507           if (cp != NULL) { 
508               /* remove the cnode from the hash table, replace the fid, and reinsert */
509               vref(CTOV(cp));
510               coda_unsave(cp);
511               cp->c_fid = out->coda_replace.NewFid;
512               coda_save(cp);
513
514               CODADEBUG(CODA_REPLACE, myprintf((
515                         "replace: oldfid = %s, newfid = %s, cp = %p\n",
516                         coda_f2s(&out->coda_replace.OldFid),
517                         coda_f2s(&cp->c_fid), cp));)          vrele(CTOV(cp));
518           }
519           return (0);
520       }
521       default:
522         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
523         return (EINVAL);
524     }
525 }
526
527 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
528
529 int
530 coda_vmflush(cp)
531      struct cnode *cp;
532 {
533     return 0;
534 }
535
536
537 /* 
538  * kernel-internal debugging switches
539  */
540 void coda_debugon(void)
541 {
542     codadebug = -1;
543     coda_nc_debug = -1;
544     coda_vnop_print_entry = 1;
545     coda_psdev_print_entry = 1;
546     coda_vfsop_print_entry = 1;
547 }
548
549 void coda_debugoff(void)
550 {
551     codadebug = 0;
552     coda_nc_debug = 0;
553     coda_vnop_print_entry = 0;
554     coda_psdev_print_entry = 0;
555     coda_vfsop_print_entry = 0;
556 }
557
558 /*
559  * Utilities used by both client and server
560  * Standard levels:
561  * 0) no debugging
562  * 1) hard failures
563  * 2) soft failures
564  * 3) current test software
565  * 4) main procedure entry points
566  * 5) main procedure exit points
567  * 6) utility procedure entry points
568  * 7) utility procedure exit points
569  * 8) obscure procedure entry points
570  * 9) obscure procedure exit points
571  * 10) random stuff
572  * 11) all <= 1
573  * 12) all <= 2
574  * 13) all <= 3
575  * ...
576  */