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/nfsclient/nfs_node.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) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)nfs_node.c  8.6 (Berkeley) 5/22/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/5.4/sys/nfsclient/nfs_node.c 141090 2005-01-31 23:27:04Z imp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/fnv_hash.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mount.h>
   44 #include <sys/namei.h>
   45 #include <sys/proc.h>
   46 #include <sys/socket.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/vnode.h>
   49 
   50 #include <vm/uma.h>
   51 
   52 #include <rpc/rpcclnt.h>
   53 
   54 #include <nfs/rpcv2.h>
   55 #include <nfs/nfsproto.h>
   56 #include <nfsclient/nfs.h>
   57 #include <nfsclient/nfsnode.h>
   58 #include <nfsclient/nfsmount.h>
   59 
   60 static uma_zone_t nfsnode_zone;
   61 static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
   62 static u_long nfsnodehash;
   63 static int nfs_node_hash_lock;
   64 
   65 #define NFSNOHASH(fhsum) \
   66         (&nfsnodehashtbl[(fhsum) & nfsnodehash])
   67 
   68 #define TRUE    1
   69 #define FALSE   0
   70 
   71 SYSCTL_DECL(_debug_hashstat);
   72 
   73 /*
   74  * Grab an atomic snapshot of the nfsnode hash chain lengths
   75  */
   76 static int
   77 sysctl_debug_hashstat_rawnfsnode(SYSCTL_HANDLER_ARGS)
   78 {
   79         int error;
   80         struct nfsnodehashhead *nnpp;
   81         struct nfsnode *nnp;
   82         int n_nfsnode;
   83         int count;
   84 
   85         n_nfsnode = nfsnodehash + 1;    /* nfsnodehash = max index, not count */
   86         if (!req->oldptr)
   87                 return SYSCTL_OUT(req, 0, n_nfsnode * sizeof(int));
   88 
   89         /* Scan hash tables for applicable entries */
   90         for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) {
   91                 count = 0;
   92                 LIST_FOREACH(nnp, nnpp, n_hash) {
   93                         count++;
   94                 }
   95                 error = SYSCTL_OUT(req, (caddr_t)&count, sizeof(count));
   96                 if (error)
   97                         return (error);
   98         }
   99         return (0);
  100 }
  101 SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnfsnode, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
  102             sysctl_debug_hashstat_rawnfsnode, "S,int", "nfsnode chain lengths");
  103 
  104 static int
  105 sysctl_debug_hashstat_nfsnode(SYSCTL_HANDLER_ARGS)
  106 {
  107         int error;
  108         struct nfsnodehashhead *nnpp;
  109         struct nfsnode *nnp;
  110         int n_nfsnode;
  111         int count, maxlength, used, pct;
  112 
  113         if (!req->oldptr)
  114                 return SYSCTL_OUT(req, 0, 4 * sizeof(int));
  115 
  116         n_nfsnode = nfsnodehash + 1;    /* nfsnodehash = max index, not count */
  117         used = 0;
  118         maxlength = 0;
  119 
  120         /* Scan hash tables for applicable entries */
  121         for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) {
  122                 count = 0;
  123                 LIST_FOREACH(nnp, nnpp, n_hash) {
  124                         count++;
  125                 }
  126                 if (count)
  127                         used++;
  128                 if (maxlength < count)
  129                         maxlength = count;
  130         }
  131         n_nfsnode = nfsnodehash + 1;
  132         pct = (used * 100 * 100) / n_nfsnode;
  133         error = SYSCTL_OUT(req, (caddr_t)&n_nfsnode, sizeof(n_nfsnode));
  134         if (error)
  135                 return (error);
  136         error = SYSCTL_OUT(req, (caddr_t)&used, sizeof(used));
  137         if (error)
  138                 return (error);
  139         error = SYSCTL_OUT(req, (caddr_t)&maxlength, sizeof(maxlength));
  140         if (error)
  141                 return (error);
  142         error = SYSCTL_OUT(req, (caddr_t)&pct, sizeof(pct));
  143         if (error)
  144                 return (error);
  145         return (0);
  146 }
  147 SYSCTL_PROC(_debug_hashstat, OID_AUTO, nfsnode, CTLTYPE_INT|CTLFLAG_RD,
  148         0, 0, sysctl_debug_hashstat_nfsnode, "I", "nfsnode chain lengths");
  149 
  150 /*
  151  * Initialize hash links for nfsnodes
  152  * and build nfsnode free list.
  153  */
  154 void
  155 nfs_nhinit(void)
  156 {
  157 
  158         nfsnode_zone = uma_zcreate("NFSNODE", sizeof(struct nfsnode), NULL,
  159             NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  160         nfsnodehashtbl = hashinit(desiredvnodes, M_NFSHASH, &nfsnodehash);
  161 }
  162 
  163 /*
  164  * Release hash table resources
  165  */
  166 void
  167 nfs_nhuninit(void)
  168 {
  169         hashdestroy(nfsnodehashtbl, M_NFSHASH, nfsnodehash);
  170         uma_zdestroy(nfsnode_zone);
  171 }
  172 
  173 /*
  174  * Look up a vnode/nfsnode by file handle.
  175  * Callers must check for mount points!!
  176  * In all cases, a pointer to a
  177  * nfsnode structure is returned.
  178  */
  179 int
  180 nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp)
  181 {
  182         struct thread *td = curthread;  /* XXX */
  183         struct nfsnode *np, *np2;
  184         struct nfsnodehashhead *nhpp;
  185         struct vnode *vp;
  186         struct vnode *nvp;
  187         int error;
  188         int rsflags;
  189         struct nfsmount *nmp;
  190 
  191         /*
  192          * Calculate nfs mount point and figure out whether the rslock should
  193          * be interruptible or not.
  194          */
  195         nmp = VFSTONFS(mntp);
  196         if (nmp->nm_flag & NFSMNT_INT)
  197                 rsflags = PCATCH;
  198         else
  199                 rsflags = 0;
  200 
  201 retry:
  202         nhpp = NFSNOHASH(fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT));
  203 loop:
  204         LIST_FOREACH(np, nhpp, n_hash) {
  205                 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize ||
  206                     bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize))
  207                         continue;
  208                 vp = NFSTOV(np);
  209                 /*
  210                  * np or vp may become invalid if vget() blocks, so loop 
  211                  */
  212                 if (vget(vp, LK_EXCLUSIVE|LK_SLEEPFAIL, td))
  213                         goto loop;
  214                 *npp = np;
  215                 return(0);
  216         }
  217         /*
  218          * Obtain a lock to prevent a race condition if the getnewvnode()
  219          * or MALLOC() below happens to block.
  220          */
  221         if (nfs_node_hash_lock) {
  222                 while (nfs_node_hash_lock) {
  223                         nfs_node_hash_lock = -1;
  224                         tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0);
  225                 }
  226                 goto loop;
  227         }
  228         nfs_node_hash_lock = 1;
  229 
  230         /*
  231          * Allocate before getnewvnode since doing so afterward
  232          * might cause a bogus v_data pointer to get dereferenced
  233          * elsewhere if zalloc should block.
  234          */
  235         np = uma_zalloc(nfsnode_zone, M_WAITOK);
  236 
  237         if (nmp->nm_flag & NFSMNT_NFSV4)
  238                 error = getnewvnode("nfs4", mntp, nfs4_vnodeop_p, &nvp);
  239         else
  240                 error = getnewvnode("nfs", mntp, nfs_vnodeop_p, &nvp);
  241         if (error) {
  242                 if (nfs_node_hash_lock < 0)
  243                         wakeup(&nfs_node_hash_lock);
  244                 nfs_node_hash_lock = 0;
  245                 *npp = 0;
  246                 uma_zfree(nfsnode_zone, np);
  247                 return (error);
  248         }
  249         vp = nvp;
  250         bzero((caddr_t)np, sizeof *np);
  251         vp->v_data = np;
  252         np->n_vnode = vp;
  253         /*
  254          * Insert the nfsnode in the hash queue for its new file handle
  255          */
  256         LIST_FOREACH(np2, nhpp, n_hash) {
  257                 if (mntp != NFSTOV(np2)->v_mount || np2->n_fhsize != fhsize ||
  258                     bcmp((caddr_t)fhp, (caddr_t)np2->n_fhp, fhsize))
  259                         continue;
  260                 vrele(vp);
  261                 if (nfs_node_hash_lock < 0)
  262                         wakeup(&nfs_node_hash_lock);
  263                 nfs_node_hash_lock = 0;
  264                 uma_zfree(nfsnode_zone, np);
  265                 goto retry;
  266         }
  267         LIST_INSERT_HEAD(nhpp, np, n_hash);
  268         if (fhsize > NFS_SMALLFH) {
  269                 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK);
  270         } else
  271                 np->n_fhp = &np->n_fh;
  272         bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
  273         np->n_fhsize = fhsize;
  274         lockinit(&np->n_rslock, PVFS | rsflags, "nfrslk", 0, LK_NOPAUSE);
  275         *npp = np;
  276 
  277         if (nfs_node_hash_lock < 0)
  278                 wakeup(&nfs_node_hash_lock);
  279         nfs_node_hash_lock = 0;
  280 
  281         /*
  282          * Lock the new nfsnode.
  283          */
  284         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  285 
  286         return (0);
  287 }
  288 
  289 int
  290 nfs_inactive(struct vop_inactive_args *ap)
  291 {
  292         struct nfsnode *np;
  293         struct sillyrename *sp;
  294         struct thread *td = curthread;  /* XXX */
  295 
  296         np = VTONFS(ap->a_vp);
  297         if (prtactive && vrefcnt(ap->a_vp) != 0)
  298                 vprint("nfs_inactive: pushing active", ap->a_vp);
  299         if (ap->a_vp->v_type != VDIR) {
  300                 sp = np->n_sillyrename;
  301                 np->n_sillyrename = NULL;
  302         } else
  303                 sp = NULL;
  304         if (sp) {
  305                 (void)nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1);
  306                 /*
  307                  * Remove the silly file that was rename'd earlier
  308                  */
  309                 (sp->s_removeit)(sp);
  310                 crfree(sp->s_cred);
  311                 vrele(sp->s_dvp);
  312                 FREE((caddr_t)sp, M_NFSREQ);
  313         }
  314         np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
  315         VOP_UNLOCK(ap->a_vp, 0, ap->a_td);
  316         return (0);
  317 }
  318 
  319 /*
  320  * Reclaim an nfsnode so that it can be used for other purposes.
  321  */
  322 int
  323 nfs_reclaim(struct vop_reclaim_args *ap)
  324 {
  325         struct vnode *vp = ap->a_vp;
  326         struct nfsnode *np = VTONFS(vp);
  327         struct nfsdmap *dp, *dp2;
  328 
  329         if (prtactive && vrefcnt(vp) != 0)
  330                 vprint("nfs_reclaim: pushing active", vp);
  331 
  332         if (np->n_hash.le_prev != NULL)         /* XXX beware */
  333                 LIST_REMOVE(np, n_hash);
  334 
  335         /*
  336          * Free up any directory cookie structures and
  337          * large file handle structures that might be associated with
  338          * this nfs node.
  339          */
  340         if (vp->v_type == VDIR) {
  341                 dp = LIST_FIRST(&np->n_cookies);
  342                 while (dp) {
  343                         dp2 = dp;
  344                         dp = LIST_NEXT(dp, ndm_list);
  345                         FREE((caddr_t)dp2, M_NFSDIROFF);
  346                 }
  347         }
  348         if (np->n_fhsize > NFS_SMALLFH) {
  349                 FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
  350         }
  351 
  352         lockdestroy(&np->n_rslock);
  353         uma_zfree(nfsnode_zone, vp->v_data);
  354         vp->v_data = NULL;
  355         return (0);
  356 }

Cache object: b38622a89b8b3e3875079353d77ad8ca


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