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.24 2007/10/10 20:42:21 ad 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.24 2007/10/10 20:42:21 ad 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(struct cnode *cp)
  126 {
  127 
  128     CNODE_NEXT(cp) = coda_freelist;
  129     coda_freelist = cp;
  130 }
  131 
  132 /*
  133  * Put a cnode in the hash table
  134  */
  135 void
  136 coda_save(struct cnode *cp)
  137 {
  138         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
  139         coda_cache[coda_hash(&cp->c_fid)] = cp;
  140 }
  141 
  142 /*
  143  * Remove a cnode from the hash table
  144  */
  145 void
  146 coda_unsave(struct cnode *cp)
  147 {
  148     struct cnode *ptr;
  149     struct cnode *ptrprev = NULL;
  150 
  151     ptr = coda_cache[coda_hash(&cp->c_fid)];
  152     while (ptr != NULL) {
  153         if (ptr == cp) {
  154             if (ptrprev == NULL) {
  155                 coda_cache[coda_hash(&cp->c_fid)]
  156                     = CNODE_NEXT(ptr);
  157             } else {
  158                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
  159             }
  160             CNODE_NEXT(cp) = (struct cnode *)NULL;
  161 
  162             return;
  163         }
  164         ptrprev = ptr;
  165         ptr = CNODE_NEXT(ptr);
  166     }
  167 }
  168 
  169 /*
  170  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
  171  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
  172  */
  173 struct cnode *
  174 coda_find(CodaFid *fid)
  175 {
  176     struct cnode *cp;
  177 
  178     cp = coda_cache[coda_hash(fid)];
  179     while (cp) {
  180         if (coda_fid_eq(&(cp->c_fid), fid) &&
  181             (!IS_UNMOUNTING(cp)))
  182             {
  183                 coda_active++;
  184                 return(cp);
  185             }
  186         cp = CNODE_NEXT(cp);
  187     }
  188     return(NULL);
  189 }
  190 
  191 /*
  192  * coda_kill is called as a side effect to vcopen. To prevent any
  193  * cnodes left around from an earlier run of a venus or warden from
  194  * causing problems with the new instance, mark any outstanding cnodes
  195  * as dying. Future operations on these cnodes should fail (excepting
  196  * coda_inactive of course!). Since multiple venii/wardens can be
  197  * running, only kill the cnodes for a particular entry in the
  198  * coda_mnttbl. -- DCS 12/1/94 */
  199 
  200 int
  201 coda_kill(struct mount *whoIam, enum dc_status dcstat)
  202 {
  203         int hash, count = 0;
  204         struct cnode *cp;
  205 
  206         /*
  207          * Algorithm is as follows:
  208          *     Second, flush whatever vnodes we can from the name cache.
  209          *
  210          *     Finally, step through whatever is left and mark them dying.
  211          *        This prevents any operation at all.
  212 
  213          */
  214 
  215         /* This is slightly overkill, but should work. Eventually it'd be
  216          * nice to only flush those entries from the namecache that
  217          * reference a vnode in this vfs.  */
  218         coda_nc_flush(dcstat);
  219 
  220         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  221                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  222                         if (CTOV(cp)->v_mount == whoIam) {
  223 #ifdef  DEBUG
  224                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
  225 #endif
  226                                 count++;
  227                                 CODADEBUG(CODA_FLUSH,
  228                                          myprintf(("Live cnode fid %s flags %d count %d\n",
  229                                                    coda_f2s(&cp->c_fid),
  230                                                    cp->c_flags,
  231                                                    CTOV(cp)->v_usecount)); );
  232                         }
  233                 }
  234         }
  235         return count;
  236 }
  237 
  238 /*
  239  * There are two reasons why a cnode may be in use, it may be in the
  240  * name cache or it may be executing.
  241  */
  242 void
  243 coda_flush(enum dc_status dcstat)
  244 {
  245     int hash;
  246     struct cnode *cp;
  247 
  248     coda_clstat.ncalls++;
  249     coda_clstat.reqs[CODA_FLUSH]++;
  250 
  251     coda_nc_flush(dcstat);          /* flush files from the name cache */
  252 
  253     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  254         for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  255             if (!IS_DIR(cp->c_fid)) /* only files can be executed */
  256                 coda_vmflush(cp);
  257         }
  258     }
  259 }
  260 
  261 /*
  262  * As a debugging measure, print out any cnodes that lived through a
  263  * name cache flush.
  264  */
  265 void
  266 coda_testflush(void)
  267 {
  268     int hash;
  269     struct cnode *cp;
  270 
  271     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  272         for (cp = coda_cache[hash];
  273              cp != NULL;
  274              cp = CNODE_NEXT(cp)) {
  275             myprintf(("Live cnode fid %s count %d\n",
  276                       coda_f2s(&cp->c_fid), 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(struct mount *whoIam)
  289 {
  290         int hash;
  291         struct cnode *cp;
  292 
  293         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  294                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  295                         if (CTOV(cp)->v_mount == whoIam) {
  296                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
  297                                         printf("coda_unmounting: Unlocking %p\n", cp);
  298                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
  299                                         wakeup((void *) cp);
  300                                 }
  301                                 cp->c_flags |= C_UNMOUNTING;
  302                         }
  303                 }
  304         }
  305 }
  306 
  307 #ifdef  DEBUG
  308 void
  309 coda_checkunmounting(struct mount *mp)
  310 {
  311         struct vnode *vp;
  312         struct cnode *cp;
  313         int count = 0, bad = 0;
  314 loop:
  315         TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
  316                 if (vp->v_mount != mp)
  317                         goto loop;
  318                 cp = VTOC(vp);
  319                 count++;
  320                 if (!(cp->c_flags & C_UNMOUNTING)) {
  321                         bad++;
  322                         printf("vp %p, cp %p missed\n", vp, cp);
  323                         cp->c_flags |= C_UNMOUNTING;
  324                 }
  325         }
  326 }
  327 
  328 void
  329 coda_cacheprint(struct mount *whoIam)
  330 {
  331         int hash;
  332         struct cnode *cp;
  333         int count = 0;
  334 
  335         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
  336         coda_nc_name(VTOC(coda_ctlvp));
  337         printf("\n");
  338 
  339         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  340                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  341                         if (CTOV(cp)->v_mount == whoIam) {
  342                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
  343                                 coda_nc_name(cp);
  344                                 printf("\n");
  345                                 count++;
  346                         }
  347                 }
  348         }
  349         printf("coda_cacheprint: count %d\n", count);
  350 }
  351 #endif
  352 
  353 /*
  354  * There are 6 cases where invalidations occur. The semantics of each
  355  * is listed here.
  356  *
  357  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
  358  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
  359  *                  This call is a result of token expiration.
  360  *
  361  * The next two are the result of callbacks on a file or directory.
  362  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
  363  *                  Zap all children of this directory from the namecache.
  364  * CODA_ZAPFILE   -- flush the attributes for a file.
  365  *
  366  * The fifth is a result of Venus detecting an inconsistent file.
  367  * CODA_PURGEFID  -- flush the attribute for the file
  368  *                  If it is a dir (odd vnode), purge its
  369  *                  children from the namecache
  370  *                  remove the file from the namecache.
  371  *
  372  * The sixth allows Venus to replace local fids with global ones
  373  * during reintegration.
  374  *
  375  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache
  376  */
  377 
  378 int handleDownCall(int opcode, union outputArgs *out)
  379 {
  380     int error;
  381 
  382     /* Handle invalidate requests. */
  383     switch (opcode) {
  384       case CODA_FLUSH : {
  385 
  386           coda_flush(IS_DOWNCALL);
  387 
  388           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
  389               return(0);
  390       }
  391 
  392       case CODA_PURGEUSER : {
  393           coda_clstat.ncalls++;
  394           coda_clstat.reqs[CODA_PURGEUSER]++;
  395 
  396           /* XXX - need to prevent fsync's */
  397 #ifdef CODA_COMPAT_5
  398           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
  399 #else
  400           coda_nc_purge_user(out->coda_purgeuser.uid, IS_DOWNCALL);
  401 #endif
  402           return(0);
  403       }
  404 
  405       case CODA_ZAPFILE : {
  406           struct cnode *cp;
  407 
  408           error = 0;
  409           coda_clstat.ncalls++;
  410           coda_clstat.reqs[CODA_ZAPFILE]++;
  411 
  412           cp = coda_find(&out->coda_zapfile.Fid);
  413           if (cp != NULL) {
  414               vref(CTOV(cp));
  415 
  416               cp->c_flags &= ~C_VATTR;
  417               if (CTOV(cp)->v_iflag & VI_TEXT)
  418                   error = coda_vmflush(cp);
  419               CODADEBUG(CODA_ZAPFILE, myprintf((
  420                     "zapfile: fid = %s, refcnt = %d, error = %d\n",
  421                     coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  422               if (CTOV(cp)->v_usecount == 1) {
  423                   cp->c_flags |= C_PURGING;
  424               }
  425               vrele(CTOV(cp));
  426           }
  427 
  428           return(error);
  429       }
  430 
  431       case CODA_ZAPDIR : {
  432           struct cnode *cp;
  433 
  434           coda_clstat.ncalls++;
  435           coda_clstat.reqs[CODA_ZAPDIR]++;
  436 
  437           cp = coda_find(&out->coda_zapdir.Fid);
  438           if (cp != NULL) {
  439               vref(CTOV(cp));
  440 
  441               cp->c_flags &= ~C_VATTR;
  442               coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL);
  443 
  444               CODADEBUG(CODA_ZAPDIR, myprintf((
  445                     "zapdir: fid = %s, refcnt = %d\n",
  446                     coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1)););
  447               if (CTOV(cp)->v_usecount == 1) {
  448                   cp->c_flags |= C_PURGING;
  449               }
  450               vrele(CTOV(cp));
  451           }
  452 
  453           return(0);
  454       }
  455 
  456       case CODA_PURGEFID : {
  457           struct cnode *cp;
  458 
  459           error = 0;
  460           coda_clstat.ncalls++;
  461           coda_clstat.reqs[CODA_PURGEFID]++;
  462 
  463           cp = coda_find(&out->coda_purgefid.Fid);
  464           if (cp != NULL) {
  465               vref(CTOV(cp));
  466               if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */
  467                   coda_nc_zapParentfid(&out->coda_purgefid.Fid,
  468                                      IS_DOWNCALL);
  469               }
  470               cp->c_flags &= ~C_VATTR;
  471               coda_nc_zapfid(&out->coda_purgefid.Fid, IS_DOWNCALL);
  472               if (!(IS_DIR(out->coda_purgefid.Fid))
  473                   && (CTOV(cp)->v_iflag & VI_TEXT)) {
  474 
  475                   error = coda_vmflush(cp);
  476               }
  477               CODADEBUG(CODA_PURGEFID, myprintf((
  478                          "purgefid: fid = %s, refcnt = %d, error = %d\n",
  479                          coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  480               if (CTOV(cp)->v_usecount == 1) {
  481                   cp->c_flags |= C_PURGING;
  482               }
  483               vrele(CTOV(cp));
  484           }
  485           return(error);
  486       }
  487 
  488       case CODA_REPLACE : {
  489           struct cnode *cp = NULL;
  490 
  491           coda_clstat.ncalls++;
  492           coda_clstat.reqs[CODA_REPLACE]++;
  493 
  494           cp = coda_find(&out->coda_replace.OldFid);
  495           if (cp != NULL) {
  496               /* remove the cnode from the hash table, replace the fid, and reinsert */
  497               vref(CTOV(cp));
  498               coda_unsave(cp);
  499               cp->c_fid = out->coda_replace.NewFid;
  500               coda_save(cp);
  501 
  502               CODADEBUG(CODA_REPLACE, myprintf((
  503                         "replace: oldfid = %s, newfid = %s, cp = %p\n",
  504                         coda_f2s(&out->coda_replace.OldFid),
  505                         coda_f2s(&cp->c_fid), 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 
  529 void coda_debugon(void)
  530 {
  531     codadebug = -1;
  532     coda_nc_debug = -1;
  533     coda_vnop_print_entry = 1;
  534     coda_psdev_print_entry = 1;
  535     coda_vfsop_print_entry = 1;
  536 }
  537 
  538 void coda_debugoff(void)
  539 {
  540     codadebug = 0;
  541     coda_nc_debug = 0;
  542     coda_vnop_print_entry = 0;
  543     coda_psdev_print_entry = 0;
  544     coda_vfsop_print_entry = 0;
  545 }
  546 
  547 /*
  548  * Utilities used by both client and server
  549  * Standard levels:
  550  * 0) no debugging
  551  * 1) hard failures
  552  * 2) soft failures
  553  * 3) current test software
  554  * 4) main procedure entry points
  555  * 5) main procedure exit points
  556  * 6) utility procedure entry points
  557  * 7) utility procedure exit points
  558  * 8) obscure procedure entry points
  559  * 9) obscure procedure exit points
  560  * 10) random stuff
  561  * 11) all <= 1
  562  * 12) all <= 2
  563  * 13) all <= 3
  564  * ...
  565  */

Cache object: c7af076a6d4a5f5e2e47d65bc62f8bbb


[ 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.