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/fs/pseudofs/pseudofs_vncache.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 /*-
    2  * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  *      $FreeBSD: releng/5.0/sys/fs/pseudofs/pseudofs_vncache.c 105165 2002-10-15 18:51:02Z phk $
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/systm.h>
   34 #include <sys/lock.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mutex.h>
   37 #include <sys/proc.h>
   38 #include <sys/sysctl.h>
   39 #include <sys/vnode.h>
   40 
   41 #include <fs/pseudofs/pseudofs.h>
   42 #include <fs/pseudofs/pseudofs_internal.h>
   43 
   44 static MALLOC_DEFINE(M_PFSVNCACHE, "pfs_vncache", "pseudofs vnode cache");
   45 
   46 static struct mtx pfs_vncache_mutex;
   47 static struct pfs_vdata *pfs_vncache;
   48 static void pfs_exit(struct proc *p);
   49 
   50 SYSCTL_NODE(_vfs_pfs, OID_AUTO, vncache, CTLFLAG_RW, 0,
   51     "pseudofs vnode cache");
   52 
   53 static int pfs_vncache_entries;
   54 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, entries, CTLFLAG_RD,
   55     &pfs_vncache_entries, 0,
   56     "number of entries in the vnode cache");
   57 
   58 static int pfs_vncache_maxentries;
   59 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, maxentries, CTLFLAG_RD,
   60     &pfs_vncache_maxentries, 0,
   61     "highest number of entries in the vnode cache");
   62 
   63 static int pfs_vncache_hits;
   64 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD,
   65     &pfs_vncache_hits, 0,
   66     "number of cache hits since initialization");
   67 
   68 static int pfs_vncache_misses;
   69 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD,
   70     &pfs_vncache_misses, 0,
   71     "number of cache misses since initialization");
   72 
   73 extern vop_t **pfs_vnodeop_p;
   74 
   75 /*
   76  * Initialize vnode cache
   77  */
   78 void
   79 pfs_vncache_load(void)
   80 {
   81         mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", NULL,
   82             MTX_DEF | MTX_RECURSE);
   83         /* XXX at_exit() can fail with ENOMEN */
   84         at_exit(pfs_exit);
   85 }
   86 
   87 /*
   88  * Tear down vnode cache
   89  */
   90 void
   91 pfs_vncache_unload(void)
   92 {
   93         rm_at_exit(pfs_exit);
   94         if (pfs_vncache_entries != 0)
   95                 printf("pfs_vncache_unload(): %d entries remaining\n",
   96                     pfs_vncache_entries);
   97         mtx_destroy(&pfs_vncache_mutex);
   98 }
   99 
  100 /*
  101  * Allocate a vnode
  102  */
  103 int
  104 pfs_vncache_alloc(struct mount *mp, struct vnode **vpp,
  105                   struct pfs_node *pn, pid_t pid)
  106 {
  107         struct pfs_vdata *pvd;
  108         int error;
  109 
  110         /*
  111          * See if the vnode is in the cache.
  112          * XXX linear search is not very efficient.
  113          */
  114         mtx_lock(&pfs_vncache_mutex);
  115         for (pvd = pfs_vncache; pvd; pvd = pvd->pvd_next) {
  116                 if (pvd->pvd_pn == pn && pvd->pvd_pid == pid) {
  117                         if (vget(pvd->pvd_vnode, 0, curthread) == 0) {
  118                                 ++pfs_vncache_hits;
  119                                 *vpp = pvd->pvd_vnode;
  120                                 mtx_unlock(&pfs_vncache_mutex);
  121                                 /* XXX see comment at top of pfs_lookup() */
  122                                 cache_purge(*vpp);
  123                                 vn_lock(*vpp, LK_RETRY | LK_EXCLUSIVE,
  124                                     curthread);
  125                                 return (0);
  126                         }
  127                         /* XXX if this can happen, we're in trouble */
  128                         break;
  129                 }
  130         }
  131         mtx_unlock(&pfs_vncache_mutex);
  132         ++pfs_vncache_misses;
  133 
  134         /* nope, get a new one */
  135         MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK);
  136         if (++pfs_vncache_entries > pfs_vncache_maxentries)
  137                 pfs_vncache_maxentries = pfs_vncache_entries;
  138         error = getnewvnode("pseudofs", mp, pfs_vnodeop_p, vpp);
  139         if (error) {
  140                 FREE(pvd, M_PFSVNCACHE);
  141                 return (error);
  142         }
  143         pvd->pvd_pn = pn;
  144         pvd->pvd_pid = pid;
  145         (*vpp)->v_data = pvd;
  146         switch (pn->pn_type) {
  147         case pfstype_root:
  148                 (*vpp)->v_vflag = VV_ROOT;
  149 #if 0
  150                 printf("root vnode allocated\n");
  151 #endif
  152                 /* fall through */
  153         case pfstype_dir:
  154         case pfstype_this:
  155         case pfstype_parent:
  156         case pfstype_procdir:
  157                 (*vpp)->v_type = VDIR;
  158                 break;
  159         case pfstype_file:
  160                 (*vpp)->v_type = VREG;
  161                 break;
  162         case pfstype_symlink:
  163                 (*vpp)->v_type = VLNK;
  164                 break;
  165         case pfstype_none:
  166                 KASSERT(0, ("pfs_vncache_alloc called for null node\n"));
  167         default:
  168                 panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type);
  169         }
  170         /*
  171          * Propagate flag through to vnode so users know it can change
  172          * if the process changes (i.e. execve)
  173          */
  174         if ((pn->pn_flags & PFS_PROCDEP) != 0)
  175                 (*vpp)->v_vflag |= VV_PROCDEP;
  176         pvd->pvd_vnode = *vpp;
  177         mtx_lock(&pfs_vncache_mutex);
  178         pvd->pvd_prev = NULL;
  179         pvd->pvd_next = pfs_vncache;
  180         if (pvd->pvd_next)
  181                 pvd->pvd_next->pvd_prev = pvd;
  182         pfs_vncache = pvd;
  183         mtx_unlock(&pfs_vncache_mutex);
  184         (*vpp)->v_vnlock->lk_flags |= LK_CANRECURSE;
  185         vn_lock(*vpp, LK_RETRY | LK_EXCLUSIVE, curthread);
  186         return (0);
  187 }
  188 
  189 /*
  190  * Free a vnode
  191  */
  192 int
  193 pfs_vncache_free(struct vnode *vp)
  194 {
  195         struct pfs_vdata *pvd;
  196 
  197         cache_purge(vp);
  198 
  199         mtx_lock(&pfs_vncache_mutex);
  200         pvd = (struct pfs_vdata *)vp->v_data;
  201         KASSERT(pvd != NULL, ("pfs_vncache_free(): no vnode data\n"));
  202         if (pvd->pvd_next)
  203                 pvd->pvd_next->pvd_prev = pvd->pvd_prev;
  204         if (pvd->pvd_prev)
  205                 pvd->pvd_prev->pvd_next = pvd->pvd_next;
  206         else
  207                 pfs_vncache = pvd->pvd_next;
  208         mtx_unlock(&pfs_vncache_mutex);
  209 
  210         --pfs_vncache_entries;
  211         FREE(pvd, M_PFSVNCACHE);
  212         vp->v_data = NULL;
  213         return (0);
  214 }
  215 
  216 /*
  217  * Free all vnodes associated with a defunct process
  218  */
  219 static void
  220 pfs_exit(struct proc *p)
  221 {
  222         struct pfs_vdata *pvd, *prev;
  223 
  224         mtx_lock(&pfs_vncache_mutex);
  225         /*
  226          * The double loop is necessary because vgone() indirectly
  227          * calls pfs_vncache_free() which frees pvd, so we have to
  228          * backtrace one step every time we free a vnode.
  229          */
  230         /* XXX linear search... not very efficient */
  231         for (pvd = pfs_vncache; pvd != NULL; pvd = pvd->pvd_next) {
  232                 while (pvd != NULL && pvd->pvd_pid == p->p_pid) {
  233                         prev = pvd->pvd_prev;
  234                         vgone(pvd->pvd_vnode);
  235                         pvd = prev ? prev->pvd_next : pfs_vncache;
  236                 }
  237                 if (pvd == NULL)
  238                         break;
  239         }
  240         mtx_unlock(&pfs_vncache_mutex);
  241 }
  242 
  243 /*
  244  * Disable a pseudofs node, and free all vnodes associated with it
  245  */
  246 int
  247 pfs_disable(struct pfs_node *pn)
  248 {
  249         struct pfs_vdata *pvd, *prev;
  250 
  251         if (pn->pn_flags & PFS_DISABLED)
  252                 return (0);
  253         mtx_lock(&pfs_vncache_mutex);
  254         pn->pn_flags |= PFS_DISABLED;
  255         /* see the comment about the double loop in pfs_exit() */
  256         /* XXX linear search... not very efficient */
  257         for (pvd = pfs_vncache; pvd != NULL; pvd = pvd->pvd_next) {
  258                 while (pvd != NULL && pvd->pvd_pn == pn) {
  259                         prev = pvd->pvd_prev;
  260                         vgone(pvd->pvd_vnode);
  261                         pvd = prev ? prev->pvd_next : pfs_vncache;
  262                 }
  263                 if (pvd == NULL)
  264                         break;
  265         }
  266         mtx_unlock(&pfs_vncache_mutex);
  267         return (0);
  268 }
  269 
  270 /*
  271  * Re-enable a disabled pseudofs node
  272  */
  273 int
  274 pfs_enable(struct pfs_node *pn)
  275 {
  276         pn->pn_flags &= ~PFS_DISABLED;
  277         return (0);
  278 }

Cache object: a338c47add88db207b8348be7e43610a


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