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/miscfs/kernfs/kernfs_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: kernfs_subr.c,v 1.7 2005/02/26 22:59:00 perry Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Jan-Simon Pendry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)kernfs_subr.c       8.6 (Berkeley) 5/14/95
   35  */
   36 
   37 /*
   38  * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
   39  * Copyright (c) 1993 Jan-Simon Pendry
   40  *
   41  * This code is derived from software contributed to Berkeley by
   42  * Jan-Simon Pendry.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  * 3. All advertising materials mentioning features or use of this software
   53  *    must display the following acknowledgement:
   54  *      This product includes software developed by the University of
   55  *      California, Berkeley and its contributors.
   56  * 4. Neither the name of the University nor the names of its contributors
   57  *    may be used to endorse or promote products derived from this software
   58  *    without specific prior written permission.
   59  *
   60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   70  * SUCH DAMAGE.
   71  *
   72  *      @(#)kernfs_subr.c       8.6 (Berkeley) 5/14/95
   73  */
   74 
   75 #include <sys/cdefs.h>
   76 __KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.7 2005/02/26 22:59:00 perry Exp $");
   77 
   78 #ifdef _KERNEL_OPT
   79 #include "opt_ipsec.h"
   80 #endif
   81 
   82 #include <sys/param.h>
   83 #include <sys/systm.h>
   84 #include <sys/time.h>
   85 #include <sys/kernel.h>
   86 #include <sys/proc.h>
   87 #include <sys/vnode.h>
   88 #include <sys/malloc.h>
   89 #include <sys/stat.h>
   90 #include <sys/file.h>
   91 #include <sys/filedesc.h>
   92 #include <sys/mount.h>
   93 
   94 #include <miscfs/kernfs/kernfs.h>
   95 
   96 #ifdef IPSEC
   97 #include <sys/mbuf.h>
   98 #include <net/route.h>
   99 #include <netinet/in.h>
  100 #include <netinet6/ipsec.h>
  101 #include <netkey/keydb.h>
  102 #include <netkey/key.h>
  103 #endif
  104 
  105 void kernfs_hashins __P((struct kernfs_node *));
  106 void kernfs_hashrem __P((struct kernfs_node *));
  107 struct vnode *kernfs_hashget __P((kfstype, struct mount *,
  108     const struct kern_target *, u_int32_t));
  109 
  110 static LIST_HEAD(kfs_hashhead, kernfs_node) *kfs_hashtbl;
  111 static u_long   kfs_ihash;      /* size of hash table - 1 */
  112 #define KFSVALUEHASH(v) ((v) & kfs_ihash)
  113 
  114 static struct lock kfs_hashlock;
  115 static struct simplelock kfs_hash_slock;
  116 
  117 #define ISSET(t, f)     ((t) & (f))
  118 
  119 /*
  120  * allocate a kfsnode/vnode pair.  the vnode is
  121  * referenced, and locked.
  122  *
  123  * the kfs_type, kfs_value and mount point uniquely
  124  * identify a kfsnode.  the mount point is needed
  125  * because someone might mount this filesystem
  126  * twice.
  127  *
  128  * all kfsnodes are maintained on a singly-linked
  129  * list.  new nodes are only allocated when they cannot
  130  * be found on this list.  entries on the list are
  131  * removed when the vfs reclaim entry is called.
  132  *
  133  * a single lock is kept for the entire list.  this is
  134  * needed because the getnewvnode() function can block
  135  * waiting for a vnode to become free, in which case there
  136  * may be more than one process trying to get the same
  137  * vnode.  this lock is only taken if we are going to
  138  * call getnewvnode, since the kernel itself is single-threaded.
  139  *
  140  * if an entry is found on the list, then call vget() to
  141  * take a reference.  this is done because there may be
  142  * zero references to it and so it needs to removed from
  143  * the vnode free list.
  144  */
  145 int
  146 kernfs_allocvp(mp, vpp, kfs_type, kt, value)
  147         struct mount *mp;
  148         struct vnode **vpp;
  149         kfstype kfs_type;
  150         const struct kern_target *kt;
  151         u_int32_t value;
  152 {
  153         struct kernfs_node *kfs = NULL, *kfsp;
  154         struct vnode *vp = NULL;
  155         int error;
  156         long *cookie;
  157 
  158         do {
  159                 if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL)
  160                         return (0);
  161         } while (lockmgr(&kfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
  162 
  163         if (kfs_type == KFSdevice) {
  164                         /* /kern/rootdev = look for device and obey */
  165                         /* /kern/rrootdev = look for device and obey */
  166                 dev_t *dp;
  167                 struct vnode *fvp;
  168 
  169 #ifdef DIAGNOSTIC
  170                 if (!kt)
  171                         panic("kernfs: kt == NULL for KFSdevice");
  172 #endif
  173                 dp = kt->kt_data;
  174         loop:
  175                 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
  176                         lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
  177                         return (ENOENT);
  178                 }
  179                 vp = fvp;
  180                 if (vget(fvp, LK_EXCLUSIVE))
  181                         goto loop;
  182                 *vpp = vp;
  183                 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
  184                 return (0);
  185         }
  186 
  187         if ((error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &vp)) != 0) {
  188                 *vpp = NULL;
  189                 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
  190                 return (error);
  191         }
  192 
  193         MALLOC(kfs, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK);
  194         memset(kfs, 0, sizeof(*kfs));
  195         vp->v_data = kfs;
  196         cookie = &(VFSTOKERNFS(mp)->fileno_cookie);
  197 again:
  198         TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) {
  199                 if (kfsp->kfs_cookie == *cookie) {
  200                         (*cookie) ++;
  201                         goto again;
  202                 }
  203                 if (TAILQ_NEXT(kfsp, kfs_list)) {
  204                         if (kfsp->kfs_cookie < *cookie &&
  205                             *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie)
  206                                 break;
  207                         if (kfsp->kfs_cookie + 1 <
  208                             TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) {
  209                                 *cookie = kfsp->kfs_cookie + 1;
  210                                 break;
  211                         }
  212                 }
  213         }
  214 
  215         kfs->kfs_cookie = *cookie;
  216 
  217         if (kfsp)
  218                 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs,
  219                     kfs_list);
  220         else
  221                 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list);
  222 
  223         kfs->kfs_type = kfs_type;
  224         kfs->kfs_vnode = vp;
  225         kfs->kfs_fileno = KERNFS_FILENO(kt, kfs_type, kfs->kfs_cookie);
  226         kfs->kfs_value = value;
  227         kfs->kfs_kt = kt;
  228         kfs->kfs_mode = kt->kt_mode;
  229         vp->v_type = kt->kt_vtype;
  230 
  231         if (kfs_type == KFSkern)
  232                 vp->v_flag = VROOT;
  233 
  234         kernfs_hashins(kfs);
  235         uvm_vnp_setsize(vp, 0);
  236         lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
  237 
  238         *vpp = vp;
  239         return (0);
  240 }
  241 
  242 int
  243 kernfs_freevp(vp)
  244         struct vnode *vp;
  245 {
  246         struct kernfs_node *kfs = VTOKERN(vp);
  247 
  248         kernfs_hashrem(kfs);
  249         TAILQ_REMOVE(&VFSTOKERNFS(vp->v_mount)->nodelist, kfs, kfs_list);
  250 
  251         FREE(vp->v_data, M_TEMP);
  252         vp->v_data = 0;
  253         return (0);
  254 }
  255 
  256 /*
  257  * Initialize kfsnode hash table.
  258  */
  259 void
  260 kernfs_hashinit()
  261 {
  262 
  263         lockinit(&kfs_hashlock, PINOD, "kfs_hashlock", 0, 0);
  264         kfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT,
  265             M_WAITOK, &kfs_ihash);
  266         simple_lock_init(&kfs_hash_slock);
  267 }
  268 
  269 void
  270 kernfs_hashreinit()
  271 {
  272         struct kernfs_node *pp;
  273         struct kfs_hashhead *oldhash, *hash;
  274         u_long i, oldmask, mask, val;
  275 
  276         hash = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT, M_WAITOK,
  277             &mask);
  278 
  279         simple_lock(&kfs_hash_slock);
  280         oldhash = kfs_hashtbl;
  281         oldmask = kfs_ihash;
  282         kfs_hashtbl = hash;
  283         kfs_ihash = mask;
  284         for (i = 0; i <= oldmask; i++) {
  285                 while ((pp = LIST_FIRST(&oldhash[i])) != NULL) {
  286                         LIST_REMOVE(pp, kfs_hash);
  287                         val = KFSVALUEHASH(pp->kfs_value);
  288                         LIST_INSERT_HEAD(&hash[val], pp, kfs_hash);
  289                 }
  290         }
  291         simple_unlock(&kfs_hash_slock);
  292         hashdone(oldhash, M_UFSMNT);
  293 }
  294 
  295 /*
  296  * Free kfsnode hash table.
  297  */
  298 void
  299 kernfs_hashdone()
  300 {
  301 
  302         hashdone(kfs_hashtbl, M_UFSMNT);
  303 }
  304 
  305 struct vnode *
  306 kernfs_hashget(type, mp, kt, value)
  307         kfstype type;
  308         struct mount *mp;
  309         const struct kern_target *kt;
  310         u_int32_t value;
  311 {
  312         struct kfs_hashhead *ppp;
  313         struct kernfs_node *pp;
  314         struct vnode *vp;
  315 
  316 loop:
  317         simple_lock(&kfs_hash_slock);
  318         ppp = &kfs_hashtbl[KFSVALUEHASH(value)];
  319         LIST_FOREACH(pp, ppp, kfs_hash) {
  320                 vp = KERNFSTOV(pp);
  321                 if (pp->kfs_type == type && vp->v_mount == mp &&
  322                     pp->kfs_kt == kt && pp->kfs_value == value) {
  323                         simple_lock(&vp->v_interlock);
  324                         simple_unlock(&kfs_hash_slock);
  325                         if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
  326                                 goto loop;
  327                         return (vp);
  328                 }
  329         }
  330         simple_unlock(&kfs_hash_slock);
  331         return (NULL);
  332 }
  333 
  334 /*
  335  * Insert the kfsnode into the hash table and lock it.
  336  */
  337 void
  338 kernfs_hashins(pp)
  339         struct kernfs_node *pp;
  340 {
  341         struct kfs_hashhead *ppp;
  342 
  343         /* lock the kfsnode, then put it on the appropriate hash list */
  344         lockmgr(&pp->kfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
  345 
  346         simple_lock(&kfs_hash_slock);
  347         ppp = &kfs_hashtbl[KFSVALUEHASH(pp->kfs_value)];
  348         LIST_INSERT_HEAD(ppp, pp, kfs_hash);
  349         simple_unlock(&kfs_hash_slock);
  350 }
  351 
  352 /*
  353  * Remove the kfsnode from the hash table.
  354  */
  355 void
  356 kernfs_hashrem(pp)
  357         struct kernfs_node *pp;
  358 {
  359         simple_lock(&kfs_hash_slock);
  360         LIST_REMOVE(pp, kfs_hash);
  361         simple_unlock(&kfs_hash_slock);
  362 }
  363 
  364 #ifdef IPSEC
  365 void
  366 kernfs_revoke_sa(sav)
  367         struct secasvar *sav;
  368 {
  369         struct kernfs_node *kfs, *pnext;
  370         struct vnode *vp;
  371         struct kfs_hashhead *ppp;
  372         struct mbuf *m;
  373 
  374         ppp = &kfs_hashtbl[KFSVALUEHASH(ntohl(sav->spi))];
  375         for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
  376                 vp = KERNFSTOV(kfs);
  377                 pnext = LIST_NEXT(kfs, kfs_hash);
  378                 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
  379                     kfs->kfs_value == ntohl(sav->spi)) {
  380                         m = key_setdumpsa_spi(sav->spi);
  381                         if (!m)
  382                                 VOP_REVOKE(vp, REVOKEALL);
  383                         else
  384                                 m_freem(m);
  385                         break;
  386                 }
  387         }
  388 }
  389 
  390 void
  391 kernfs_revoke_sp(sp)
  392         struct secpolicy *sp;
  393 {
  394         struct kernfs_node *kfs, *pnext;
  395         struct vnode *vp;
  396         struct kfs_hashhead *ppp;
  397 
  398         ppp = &kfs_hashtbl[KFSVALUEHASH(sp->id)];
  399         for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
  400                 vp = KERNFSTOV(kfs);
  401                 pnext = LIST_NEXT(kfs, kfs_hash);
  402                 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
  403                     kfs->kfs_value == sp->id)
  404                         VOP_REVOKE(vp, REVOKEALL);
  405         }
  406 }
  407 #endif

Cache object: 4ecf62f551af3404aee21b6c8446a683


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