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/kern/vfs_cache.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: vfs_cache.c,v 1.54.2.2 2004/07/23 23:48:21 he Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)vfs_cache.c 8.3 (Berkeley) 8/22/94
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: vfs_cache.c,v 1.54.2.2 2004/07/23 23:48:21 he Exp $");
   36 
   37 #include "opt_ddb.h"
   38 #include "opt_revcache.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/time.h>
   43 #include <sys/mount.h>
   44 #include <sys/vnode.h>
   45 #include <sys/namei.h>
   46 #include <sys/errno.h>
   47 #include <sys/malloc.h>
   48 #include <sys/pool.h>
   49 #include <sys/lock.h>
   50 
   51 /*
   52  * Name caching works as follows:
   53  *
   54  * Names found by directory scans are retained in a cache
   55  * for future reference.  It is managed LRU, so frequently
   56  * used names will hang around.  Cache is indexed by hash value
   57  * obtained from (dvp, name) where dvp refers to the directory
   58  * containing name.
   59  *
   60  * For simplicity (and economy of storage), names longer than
   61  * a maximum length of NCHNAMLEN are not cached; they occur
   62  * infrequently in any case, and are almost never of interest.
   63  *
   64  * Upon reaching the last segment of a path, if the reference
   65  * is for DELETE, or NOCACHE is set (rewrite), and the
   66  * name is located in the cache, it will be dropped.
   67  * The entry is dropped also when it was not possible to lock
   68  * the cached vnode, either because vget() failed or the generation
   69  * number has changed while waiting for the lock.
   70  */
   71 
   72 /*
   73  * Structures associated with name cacheing.
   74  */
   75 LIST_HEAD(nchashhead, namecache) *nchashtbl;
   76 u_long  nchash;                         /* size of hash table - 1 */
   77 long    numcache;                       /* number of cache entries allocated */
   78 #define NCHASH(cnp, dvp)        \
   79         (((cnp)->cn_hash ^ ((uintptr_t)(dvp) >> 3)) & nchash)
   80 
   81 LIST_HEAD(ncvhashhead, namecache) *ncvhashtbl;
   82 u_long  ncvhash;                        /* size of hash table - 1 */
   83 #define NCVHASH(vp)             (((uintptr_t)(vp) >> 3) & ncvhash)
   84 
   85 TAILQ_HEAD(, namecache) nclruhead;              /* LRU chain */
   86 struct  nchstats nchstats;              /* cache effectiveness statistics */
   87 
   88 struct pool namecache_pool;
   89 
   90 MALLOC_DEFINE(M_CACHE, "namecache", "Dynamically allocated cache entries");
   91 
   92 int doingcache = 1;                     /* 1 => enable the cache */
   93 
   94 /* A single lock to protect cache insertion, removal and lookup */
   95 static struct simplelock namecache_slock = SIMPLELOCK_INITIALIZER;
   96 
   97 static void cache_remove(struct namecache *);
   98 static void cache_free(struct namecache *);
   99 static __inline struct namecache *cache_lookup_entry(
  100     const struct vnode *, const struct componentname *);
  101 
  102 static void
  103 cache_remove(struct namecache *ncp)
  104 {
  105 
  106         LOCK_ASSERT(simple_lock_held(&namecache_slock));
  107 
  108         ncp->nc_dvp = NULL;
  109         ncp->nc_vp = NULL;
  110 
  111         TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
  112         if (ncp->nc_hash.le_prev != NULL) {
  113                 LIST_REMOVE(ncp, nc_hash);
  114                 ncp->nc_hash.le_prev = NULL;
  115         }
  116         if (ncp->nc_vhash.le_prev != NULL) {
  117                 LIST_REMOVE(ncp, nc_vhash);
  118                 ncp->nc_vhash.le_prev = NULL;
  119         }
  120         if (ncp->nc_vlist.le_prev != NULL) {
  121                 LIST_REMOVE(ncp, nc_vlist);
  122                 ncp->nc_vlist.le_prev = NULL;
  123         }
  124         if (ncp->nc_dvlist.le_prev != NULL) {
  125                 LIST_REMOVE(ncp, nc_dvlist);
  126                 ncp->nc_dvlist.le_prev = NULL;
  127         }
  128 }
  129 
  130 static void
  131 cache_free(struct namecache *ncp)
  132 {
  133 
  134         pool_put(&namecache_pool, ncp);
  135         numcache--;
  136 }
  137 
  138 static __inline struct namecache *
  139 cache_lookup_entry(const struct vnode *dvp, const struct componentname *cnp)
  140 {
  141         struct nchashhead *ncpp;
  142         struct namecache *ncp;
  143 
  144         LOCK_ASSERT(simple_lock_held(&namecache_slock));
  145 
  146         ncpp = &nchashtbl[NCHASH(cnp, dvp)];
  147 
  148         LIST_FOREACH(ncp, ncpp, nc_hash) {
  149                 if (ncp->nc_dvp == dvp &&
  150                     ncp->nc_nlen == cnp->cn_namelen &&
  151                     !memcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
  152                         break;
  153         }
  154 
  155         return ncp;
  156 }
  157 
  158 /*
  159  * Look for a the name in the cache. We don't do this
  160  * if the segment name is long, simply so the cache can avoid
  161  * holding long names (which would either waste space, or
  162  * add greatly to the complexity).
  163  *
  164  * Lookup is called with ni_dvp pointing to the directory to search,
  165  * ni_ptr pointing to the name of the entry being sought, ni_namelen
  166  * tells the length of the name, and ni_hash contains a hash of
  167  * the name. If the lookup succeeds, the vnode is locked, stored in ni_vp
  168  * and a status of zero is returned. If the locking fails for whatever
  169  * reason, the vnode is unlocked and the error is returned to caller.
  170  * If the lookup determines that the name does not exist (negative cacheing),
  171  * a status of ENOENT is returned. If the lookup fails, a status of -1
  172  * is returned.
  173  */
  174 int
  175 cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
  176 {
  177         struct namecache *ncp;
  178         struct vnode *vp;
  179         int error;
  180 
  181         if (!doingcache) {
  182                 cnp->cn_flags &= ~MAKEENTRY;
  183                 *vpp = NULL;
  184                 return (-1);
  185         }
  186 
  187         if (cnp->cn_namelen > NCHNAMLEN) {
  188                 /* XXXSMP - updating stats without lock; do we care? */
  189                 nchstats.ncs_long++;
  190                 cnp->cn_flags &= ~MAKEENTRY;
  191                 goto fail;
  192         }
  193         simple_lock(&namecache_slock);
  194         ncp = cache_lookup_entry(dvp, cnp);
  195         if (ncp == NULL) {
  196                 nchstats.ncs_miss++;
  197                 goto fail_wlock;
  198         }
  199         if ((cnp->cn_flags & MAKEENTRY) == 0) {
  200                 nchstats.ncs_badhits++;
  201                 goto remove;
  202         } else if (ncp->nc_vp == NULL) {
  203                 /*
  204                  * Restore the ISWHITEOUT flag saved earlier.
  205                  */
  206                 cnp->cn_flags |= ncp->nc_flags;
  207                 if (cnp->cn_nameiop != CREATE ||
  208                     (cnp->cn_flags & ISLASTCN) == 0) {
  209                         nchstats.ncs_neghits++;
  210                         /*
  211                          * Move this slot to end of LRU chain,
  212                          * if not already there.
  213                          */
  214                         if (TAILQ_NEXT(ncp, nc_lru) != 0) {
  215                                 TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
  216                                 TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
  217                         }
  218                         simple_unlock(&namecache_slock);
  219                         return (ENOENT);
  220                 } else {
  221                         nchstats.ncs_badhits++;
  222                         goto remove;
  223                 }
  224         }
  225 
  226         vp = ncp->nc_vp;
  227 
  228         /*
  229          * Move this slot to end of LRU chain, if not already there.
  230          */
  231         if (TAILQ_NEXT(ncp, nc_lru) != 0) {
  232                 TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
  233                 TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
  234         }
  235 
  236         if (vp != dvp)
  237                 simple_lock(&vp->v_interlock);
  238 
  239         /* Release the name cache mutex while we acquire vnode locks */
  240         simple_unlock(&namecache_slock);
  241 
  242 #ifdef DEBUG
  243         /*
  244          * since we released namecache_slock,
  245          * we can't use this pointer any more.
  246          */
  247         ncp = NULL;
  248 #endif /* DEBUG */
  249 
  250         if (vp != dvp && __predict_false(vp->v_flag & VXLOCK)) {
  251                 /*
  252                  * this vnode is being cleaned out.
  253                  */
  254                 simple_unlock(&vp->v_interlock);
  255                 nchstats.ncs_falsehits++; /* XXX badhits? */
  256                 goto fail;
  257         }
  258 
  259         if (vp == dvp) {        /* lookup on "." */
  260                 VREF(dvp);
  261                 error = 0;
  262         } else if (cnp->cn_flags & ISDOTDOT) {
  263                 VOP_UNLOCK(dvp, 0);
  264                 cnp->cn_flags |= PDIRUNLOCK;
  265                 error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK);
  266                 /*
  267                  * If the above vget() succeeded and both LOCKPARENT and
  268                  * ISLASTCN is set, lock the directory vnode as well.
  269                  */
  270                 if (!error && (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) == 0) {
  271                         if ((error = vn_lock(dvp, LK_EXCLUSIVE)) != 0) {
  272                                 vput(vp);
  273                                 return (error);
  274                         }
  275                         cnp->cn_flags &= ~PDIRUNLOCK;
  276                 }
  277         } else {
  278                 error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK);
  279                 /*
  280                  * If the above vget() failed or either of LOCKPARENT or
  281                  * ISLASTCN is set, unlock the directory vnode.
  282                  */
  283                 if (error || (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) != 0) {
  284                         VOP_UNLOCK(dvp, 0);
  285                         cnp->cn_flags |= PDIRUNLOCK;
  286                 }
  287         }
  288 
  289         /*
  290          * Check that the lock succeeded.
  291          */
  292         if (error) {
  293                 /* XXXSMP - updating stats without lock; do we care? */
  294                 nchstats.ncs_badhits++;
  295 
  296                 /*
  297                  * The parent needs to be locked when we return to VOP_LOOKUP().
  298                  * The `.' case here should be extremely rare (if it can happen
  299                  * at all), so we don't bother optimizing out the unlock/relock.
  300                  */
  301                 if (vp == dvp ||
  302                     error || (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) != 0) {
  303                         if ((error = vn_lock(dvp, LK_EXCLUSIVE)) != 0)
  304                                 return (error);
  305                         cnp->cn_flags &= ~PDIRUNLOCK;
  306                 }
  307                 *vpp = NULL;
  308                 return (-1);
  309         }
  310 
  311         /* XXXSMP - updating stats without lock; do we care? */
  312         nchstats.ncs_goodhits++;
  313         *vpp = vp;
  314         return (0);
  315 
  316 remove:
  317         /*
  318          * Last component and we are renaming or deleting,
  319          * the cache entry is invalid, or otherwise don't
  320          * want cache entry to exist.
  321          */
  322         cache_remove(ncp);
  323         cache_free(ncp);
  324 
  325 fail_wlock:
  326         simple_unlock(&namecache_slock);
  327 fail:
  328         *vpp = NULL;
  329         return (-1);
  330 }
  331 
  332 /*
  333  * Scan cache looking for name of directory entry pointing at vp.
  334  *
  335  * Fill in dvpp.
  336  *
  337  * If bufp is non-NULL, also place the name in the buffer which starts
  338  * at bufp, immediately before *bpp, and move bpp backwards to point
  339  * at the start of it.  (Yes, this is a little baroque, but it's done
  340  * this way to cater to the whims of getcwd).
  341  *
  342  * Returns 0 on success, -1 on cache miss, positive errno on failure.
  343  */
  344 int
  345 cache_revlookup(struct vnode *vp, struct vnode **dvpp, char **bpp, char *bufp)
  346 {
  347         struct namecache *ncp;
  348         struct vnode *dvp;
  349         struct ncvhashhead *nvcpp;
  350         char *bp;
  351 
  352         if (!doingcache)
  353                 goto out;
  354 
  355         nvcpp = &ncvhashtbl[NCVHASH(vp)];
  356 
  357         simple_lock(&namecache_slock);
  358         LIST_FOREACH(ncp, nvcpp, nc_vhash) {
  359                 if (ncp->nc_vp == vp &&
  360                     (dvp = ncp->nc_dvp) != NULL &&
  361                     dvp != vp) {                /* avoid pesky . entries.. */
  362 
  363 #ifdef DIAGNOSTIC
  364                         if (ncp->nc_nlen == 1 &&
  365                             ncp->nc_name[0] == '.')
  366                                 panic("cache_revlookup: found entry for .");
  367 
  368                         if (ncp->nc_nlen == 2 &&
  369                             ncp->nc_name[0] == '.' &&
  370                             ncp->nc_name[1] == '.')
  371                                 panic("cache_revlookup: found entry for ..");
  372 #endif
  373                         nchstats.ncs_revhits++;
  374 
  375                         if (bufp) {
  376                                 bp = *bpp;
  377                                 bp -= ncp->nc_nlen;
  378                                 if (bp <= bufp) {
  379                                         *dvpp = NULL;
  380                                         simple_unlock(&namecache_slock);
  381                                         return (ERANGE);
  382                                 }
  383                                 memcpy(bp, ncp->nc_name, ncp->nc_nlen);
  384                                 *bpp = bp;
  385                         }
  386 
  387                         /* XXX MP: how do we know dvp won't evaporate? */
  388                         *dvpp = dvp;
  389                         simple_unlock(&namecache_slock);
  390                         return (0);
  391                 }
  392         }
  393         nchstats.ncs_revmiss++;
  394         simple_unlock(&namecache_slock);
  395  out:
  396         *dvpp = NULL;
  397         return (-1);
  398 }
  399 
  400 /*
  401  * Add an entry to the cache
  402  */
  403 void
  404 cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
  405 {
  406         struct namecache *ncp;
  407         struct nchashhead *ncpp;
  408         struct ncvhashhead *nvcpp;
  409 
  410 #ifdef DIAGNOSTIC
  411         if (cnp->cn_namelen > NCHNAMLEN)
  412                 panic("cache_enter: name too long");
  413 #endif
  414         if (!doingcache)
  415                 return;
  416         /*
  417          * Free the cache slot at head of lru chain.
  418          */
  419         simple_lock(&namecache_slock);
  420         if (numcache < numvnodes) {
  421                 numcache++;
  422                 simple_unlock(&namecache_slock);
  423                 ncp = pool_get(&namecache_pool, PR_WAITOK);
  424                 memset(ncp, 0, sizeof(*ncp));
  425                 simple_lock(&namecache_slock);
  426         } else if ((ncp = TAILQ_FIRST(&nclruhead)) != NULL) {
  427                 cache_remove(ncp);
  428         } else {
  429                 simple_unlock(&namecache_slock);
  430                 return;
  431         }
  432 
  433         /*
  434          * Concurrent lookups in the same directory may race for a
  435          * cache entry. If we loose, free our tentative entry and return.
  436          */
  437         if (cache_lookup_entry(dvp, cnp) != NULL) {
  438                 cache_free(ncp);
  439                 simple_unlock(&namecache_slock);
  440                 return;
  441         }
  442 
  443         /* Grab the vnode we just found. */
  444         ncp->nc_vp = vp;
  445         if (vp == NULL) {
  446                 /*
  447                  * For negative hits, save the ISWHITEOUT flag so we can
  448                  * restore it later when the cache entry is used again.
  449                  */
  450                 ncp->nc_flags = cnp->cn_flags & ISWHITEOUT;
  451         }
  452         /* Fill in cache info. */
  453         ncp->nc_dvp = dvp;
  454         LIST_INSERT_HEAD(&dvp->v_dnclist, ncp, nc_dvlist);
  455         if (vp)
  456                 LIST_INSERT_HEAD(&vp->v_nclist, ncp, nc_vlist);
  457         ncp->nc_nlen = cnp->cn_namelen;
  458         memcpy(ncp->nc_name, cnp->cn_nameptr, (unsigned)ncp->nc_nlen);
  459         TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
  460         ncpp = &nchashtbl[NCHASH(cnp, dvp)];
  461         LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
  462 
  463         ncp->nc_vhash.le_prev = NULL;
  464         ncp->nc_vhash.le_next = NULL;
  465 
  466         /*
  467          * Create reverse-cache entries (used in getcwd) for directories.
  468          */
  469         if (vp != NULL &&
  470             vp != dvp &&
  471 #ifndef NAMECACHE_ENTER_REVERSE
  472             vp->v_type == VDIR &&
  473 #endif
  474             (ncp->nc_nlen > 2 ||
  475             (ncp->nc_nlen > 1 && ncp->nc_name[1] != '.') ||
  476             (/* ncp->nc_nlen > 0 && */ ncp->nc_name[0] != '.'))) {
  477                 nvcpp = &ncvhashtbl[NCVHASH(vp)];
  478                 LIST_INSERT_HEAD(nvcpp, ncp, nc_vhash);
  479         }
  480         simple_unlock(&namecache_slock);
  481 }
  482 
  483 /*
  484  * Name cache initialization, from vfs_init() when we are booting
  485  */
  486 void
  487 nchinit(void)
  488 {
  489 
  490         TAILQ_INIT(&nclruhead);
  491         nchashtbl =
  492             hashinit(desiredvnodes, HASH_LIST, M_CACHE, M_WAITOK, &nchash);
  493         ncvhashtbl =
  494 #ifdef NAMECACHE_ENTER_REVERSE
  495             hashinit(desiredvnodes, HASH_LIST, M_CACHE, M_WAITOK, &ncvhash);
  496 #else
  497             hashinit(desiredvnodes/8, HASH_LIST, M_CACHE, M_WAITOK, &ncvhash);
  498 #endif
  499         pool_init(&namecache_pool, sizeof(struct namecache), 0, 0, 0,
  500             "ncachepl", &pool_allocator_nointr);
  501 }
  502 
  503 /*
  504  * Name cache reinitialization, for when the maximum number of vnodes increases.
  505  */
  506 void
  507 nchreinit(void)
  508 {
  509         struct namecache *ncp;
  510         struct nchashhead *oldhash1, *hash1;
  511         struct ncvhashhead *oldhash2, *hash2;
  512         u_long i, oldmask1, oldmask2, mask1, mask2;
  513 
  514         hash1 = hashinit(desiredvnodes, HASH_LIST, M_CACHE, M_WAITOK, &mask1);
  515         hash2 =
  516 #ifdef NAMECACHE_ENTER_REVERSE
  517             hashinit(desiredvnodes, HASH_LIST, M_CACHE, M_WAITOK, &mask2);
  518 #else
  519             hashinit(desiredvnodes/8, HASH_LIST, M_CACHE, M_WAITOK, &mask2);
  520 #endif
  521         simple_lock(&namecache_slock);
  522         oldhash1 = nchashtbl;
  523         oldmask1 = nchash;
  524         nchashtbl = hash1;
  525         nchash = mask1;
  526         oldhash2 = ncvhashtbl;
  527         oldmask2 = ncvhash;
  528         ncvhashtbl = hash2;
  529         ncvhash = mask2;
  530         for (i = 0; i <= oldmask1; i++) {
  531                 while ((ncp = LIST_FIRST(&oldhash1[i])) != NULL) {
  532                         LIST_REMOVE(ncp, nc_hash);
  533                         ncp->nc_hash.le_prev = NULL;
  534                 }
  535         }
  536         for (i = 0; i <= oldmask2; i++) {
  537                 while ((ncp = LIST_FIRST(&oldhash2[i])) != NULL) {
  538                         LIST_REMOVE(ncp, nc_vhash);
  539                         ncp->nc_vhash.le_prev = NULL;
  540                 }
  541         }
  542         simple_unlock(&namecache_slock);
  543         hashdone(oldhash1, M_CACHE);
  544         hashdone(oldhash2, M_CACHE);
  545 }
  546 
  547 /*
  548  * Cache flush, a particular vnode; called when a vnode is renamed to
  549  * hide entries that would now be invalid
  550  */
  551 void
  552 cache_purge1(struct vnode *vp, const struct componentname *cnp, int flags)
  553 {
  554         struct namecache *ncp, *ncnext;
  555 
  556         simple_lock(&namecache_slock);
  557         if (flags & PURGE_PARENTS) {
  558                 for (ncp = LIST_FIRST(&vp->v_nclist); ncp != NULL;
  559                     ncp = ncnext) {
  560                         ncnext = LIST_NEXT(ncp, nc_vlist);
  561                         cache_remove(ncp);
  562                         cache_free(ncp);
  563                 }
  564         }
  565         if (flags & PURGE_CHILDREN) {
  566                 for (ncp = LIST_FIRST(&vp->v_dnclist); ncp != NULL;
  567                     ncp = ncnext) {
  568                         ncnext = LIST_NEXT(ncp, nc_dvlist);
  569                         cache_remove(ncp);
  570                         cache_free(ncp);
  571                 }
  572         }
  573         if (cnp != NULL) {
  574                 ncp = cache_lookup_entry(vp, cnp);
  575                 if (ncp) {
  576                         cache_remove(ncp);
  577                         cache_free(ncp);
  578                 }
  579         }
  580         simple_unlock(&namecache_slock);
  581 }
  582 
  583 /*
  584  * Cache flush, a whole filesystem; called when filesys is umounted to
  585  * remove entries that would now be invalid.
  586  */
  587 void
  588 cache_purgevfs(struct mount *mp)
  589 {
  590         struct namecache *ncp, *nxtcp;
  591 
  592         simple_lock(&namecache_slock);
  593         for (ncp = TAILQ_FIRST(&nclruhead); ncp != NULL; ncp = nxtcp) {
  594                 nxtcp = TAILQ_NEXT(ncp, nc_lru);
  595                 if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) {
  596                         continue;
  597                 }
  598                 /* Free the resources we had. */
  599                 cache_remove(ncp);
  600                 cache_free(ncp);
  601         }
  602         simple_unlock(&namecache_slock);
  603 }
  604 
  605 #ifdef DDB
  606 void
  607 namecache_print(struct vnode *vp, void (*pr)(const char *, ...))
  608 {
  609         struct vnode *dvp = NULL;
  610         struct namecache *ncp;
  611 
  612         TAILQ_FOREACH(ncp, &nclruhead, nc_lru) {
  613                 if (ncp->nc_vp == vp) {
  614                         (*pr)("name %.*s\n", ncp->nc_nlen, ncp->nc_name);
  615                         dvp = ncp->nc_dvp;
  616                 }
  617         }
  618         if (dvp == NULL) {
  619                 (*pr)("name not found\n");
  620                 return;
  621         }
  622         vp = dvp;
  623         TAILQ_FOREACH(ncp, &nclruhead, nc_lru) {
  624                 if (ncp->nc_vp == vp) {
  625                         (*pr)("parent %.*s\n", ncp->nc_nlen, ncp->nc_name);
  626                 }
  627         }
  628 }
  629 #endif

Cache object: b33e724e600d3cb29b815b5ebf8d4eac


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