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

Cache object: 330a7a8424fedace5583802f1416c125


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