The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/coda/coda_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e56a9ce7805154a928c1ab0c8612a27a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.