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.1/sys/nfsclient/nfs_node.c 111119 2003-02-19 05:47:46Z imp $");
   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 <nfs/rpcv2.h>
   57 #include <nfs/nfsproto.h>
   58 #include <nfsclient/nfs.h>
   59 #include <nfsclient/nfsnode.h>
   60 #include <nfsclient/nfsmount.h>
   61 
   62 static uma_zone_t nfsnode_zone;
   63 static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
   64 static u_long nfsnodehash;
   65 static int nfs_node_hash_lock;
   66 
   67 #define NFSNOHASH(fhsum) \
   68         (&nfsnodehashtbl[(fhsum) & nfsnodehash])
   69 
   70 #define TRUE    1
   71 #define FALSE   0
   72 
   73 SYSCTL_DECL(_debug_hashstat);
   74 
   75 /*
   76  * Grab an atomic snapshot of the nfsnode hash chain lengths
   77  */
   78 static int
   79 sysctl_debug_hashstat_rawnfsnode(SYSCTL_HANDLER_ARGS)
   80 {
   81         int error;
   82         struct nfsnodehashhead *nnpp;
   83         struct nfsnode *nnp;
   84         int n_nfsnode;
   85         int count;
   86 
   87         n_nfsnode = nfsnodehash + 1;    /* nfsnodehash = max index, not count */
   88         if (!req->oldptr)
   89                 return SYSCTL_OUT(req, 0, n_nfsnode * sizeof(int));
   90 
   91         /* Scan hash tables for applicable entries */
   92         for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) {
   93                 count = 0;
   94                 LIST_FOREACH(nnp, nnpp, n_hash) {
   95                         count++;
   96                 }
   97                 error = SYSCTL_OUT(req, (caddr_t)&count, sizeof(count));
   98                 if (error)
   99                         return (error);
  100         }
  101         return (0);
  102 }
  103 SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnfsnode, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
  104             sysctl_debug_hashstat_rawnfsnode, "S,int", "nfsnode chain lengths");
  105 
  106 static int
  107 sysctl_debug_hashstat_nfsnode(SYSCTL_HANDLER_ARGS)
  108 {
  109         int error;
  110         struct nfsnodehashhead *nnpp;
  111         struct nfsnode *nnp;
  112         int n_nfsnode;
  113         int count, maxlength, used, pct;
  114 
  115         if (!req->oldptr)
  116                 return SYSCTL_OUT(req, 0, 4 * sizeof(int));
  117 
  118         n_nfsnode = nfsnodehash + 1;    /* nfsnodehash = max index, not count */
  119         used = 0;
  120         maxlength = 0;
  121 
  122         /* Scan hash tables for applicable entries */
  123         for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) {
  124                 count = 0;
  125                 LIST_FOREACH(nnp, nnpp, n_hash) {
  126                         count++;
  127                 }
  128                 if (count)
  129                         used++;
  130                 if (maxlength < count)
  131                         maxlength = count;
  132         }
  133         n_nfsnode = nfsnodehash + 1;
  134         pct = (used * 100 * 100) / n_nfsnode;
  135         error = SYSCTL_OUT(req, (caddr_t)&n_nfsnode, sizeof(n_nfsnode));
  136         if (error)
  137                 return (error);
  138         error = SYSCTL_OUT(req, (caddr_t)&used, sizeof(used));
  139         if (error)
  140                 return (error);
  141         error = SYSCTL_OUT(req, (caddr_t)&maxlength, sizeof(maxlength));
  142         if (error)
  143                 return (error);
  144         error = SYSCTL_OUT(req, (caddr_t)&pct, sizeof(pct));
  145         if (error)
  146                 return (error);
  147         return (0);
  148 }
  149 SYSCTL_PROC(_debug_hashstat, OID_AUTO, nfsnode, CTLTYPE_INT|CTLFLAG_RD,
  150         0, 0, sysctl_debug_hashstat_nfsnode, "I", "nfsnode chain lengths");
  151 
  152 /*
  153  * Initialize hash links for nfsnodes
  154  * and build nfsnode free list.
  155  */
  156 void
  157 nfs_nhinit(void)
  158 {
  159 
  160         nfsnode_zone = uma_zcreate("NFSNODE", sizeof(struct nfsnode), NULL,
  161             NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  162         nfsnodehashtbl = hashinit(desiredvnodes, M_NFSHASH, &nfsnodehash);
  163 }
  164 
  165 /*
  166  * Look up a vnode/nfsnode by file handle.
  167  * Callers must check for mount points!!
  168  * In all cases, a pointer to a
  169  * nfsnode structure is returned.
  170  */
  171 int
  172 nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp)
  173 {
  174         struct thread *td = curthread;  /* XXX */
  175         struct nfsnode *np, *np2;
  176         struct nfsnodehashhead *nhpp;
  177         struct vnode *vp;
  178         struct vnode *nvp;
  179         int error;
  180         int rsflags;
  181         struct nfsmount *nmp;
  182 
  183         /*
  184          * Calculate nfs mount point and figure out whether the rslock should
  185          * be interruptable or not.
  186          */
  187         nmp = VFSTONFS(mntp);
  188         if (nmp->nm_flag & NFSMNT_INT)
  189                 rsflags = PCATCH;
  190         else
  191                 rsflags = 0;
  192 
  193 retry:
  194         nhpp = NFSNOHASH(fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT));
  195 loop:
  196         LIST_FOREACH(np, nhpp, n_hash) {
  197                 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize ||
  198                     bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize))
  199                         continue;
  200                 vp = NFSTOV(np);
  201                 /*
  202                  * np or vp may become invalid if vget() blocks, so loop 
  203                  */
  204                 if (vget(vp, LK_EXCLUSIVE|LK_SLEEPFAIL, td))
  205                         goto loop;
  206                 *npp = np;
  207                 return(0);
  208         }
  209         /*
  210          * Obtain a lock to prevent a race condition if the getnewvnode()
  211          * or MALLOC() below happens to block.
  212          */
  213         if (nfs_node_hash_lock) {
  214                 while (nfs_node_hash_lock) {
  215                         nfs_node_hash_lock = -1;
  216                         tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0);
  217                 }
  218                 goto loop;
  219         }
  220         nfs_node_hash_lock = 1;
  221 
  222         /*
  223          * Allocate before getnewvnode since doing so afterward
  224          * might cause a bogus v_data pointer to get dereferenced
  225          * elsewhere if zalloc should block.
  226          */
  227         np = uma_zalloc(nfsnode_zone, M_WAITOK);
  228 
  229         error = getnewvnode("nfs", mntp, nfsv2_vnodeop_p, &nvp);
  230         if (error) {
  231                 if (nfs_node_hash_lock < 0)
  232                         wakeup(&nfs_node_hash_lock);
  233                 nfs_node_hash_lock = 0;
  234                 *npp = 0;
  235                 uma_zfree(nfsnode_zone, np);
  236                 return (error);
  237         }
  238         vp = nvp;
  239         bzero((caddr_t)np, sizeof *np);
  240         vp->v_data = np;
  241         np->n_vnode = vp;
  242         /*
  243          * Insert the nfsnode in the hash queue for its new file handle
  244          */
  245         LIST_FOREACH(np2, nhpp, n_hash) {
  246                 if (mntp != NFSTOV(np2)->v_mount || np2->n_fhsize != fhsize ||
  247                     bcmp((caddr_t)fhp, (caddr_t)np2->n_fhp, fhsize))
  248                         continue;
  249                 vrele(vp);
  250                 if (nfs_node_hash_lock < 0)
  251                         wakeup(&nfs_node_hash_lock);
  252                 nfs_node_hash_lock = 0;
  253                 uma_zfree(nfsnode_zone, np);
  254                 goto retry;
  255         }
  256         LIST_INSERT_HEAD(nhpp, np, n_hash);
  257         if (fhsize > NFS_SMALLFH) {
  258                 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK);
  259         } else
  260                 np->n_fhp = &np->n_fh;
  261         bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
  262         np->n_fhsize = fhsize;
  263         lockinit(&np->n_rslock, PVFS | rsflags, "nfrslk", 0, LK_NOPAUSE);
  264         *npp = np;
  265 
  266         if (nfs_node_hash_lock < 0)
  267                 wakeup(&nfs_node_hash_lock);
  268         nfs_node_hash_lock = 0;
  269 
  270         /*
  271          * Lock the new nfsnode.
  272          */
  273         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  274 
  275         return (0);
  276 }
  277 
  278 int
  279 nfs_inactive(struct vop_inactive_args *ap)
  280 {
  281         struct nfsnode *np;
  282         struct sillyrename *sp;
  283         struct thread *td = curthread;  /* XXX */
  284 
  285         np = VTONFS(ap->a_vp);
  286         if (prtactive && vrefcnt(ap->a_vp) != 0)
  287                 vprint("nfs_inactive: pushing active", ap->a_vp);
  288         if (ap->a_vp->v_type != VDIR) {
  289                 sp = np->n_sillyrename;
  290                 np->n_sillyrename = NULL;
  291         } else
  292                 sp = NULL;
  293         if (sp) {
  294                 /*
  295                  * We need a reference to keep the vnode from being
  296                  * recycled by getnewvnode while we do the I/O
  297                  * associated with discarding the buffers unless we
  298                  * are being forcibly unmounted in which case we already
  299                  * have our own reference.
  300                  */
  301                 if (vrefcnt(ap->a_vp) > 0)
  302                         (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1);
  303                 else if (vget(ap->a_vp, 0, td))
  304                         panic("nfs_inactive: lost vnode");
  305                 else {
  306                         (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1);
  307                         vrele(ap->a_vp);
  308                 }
  309                 /*
  310                  * Remove the silly file that was rename'd earlier
  311                  */
  312                 nfs_removeit(sp);
  313                 crfree(sp->s_cred);
  314                 vrele(sp->s_dvp);
  315                 FREE((caddr_t)sp, M_NFSREQ);
  316         }
  317         np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
  318         VOP_UNLOCK(ap->a_vp, 0, ap->a_td);
  319         return (0);
  320 }
  321 
  322 /*
  323  * Reclaim an nfsnode so that it can be used for other purposes.
  324  */
  325 int
  326 nfs_reclaim(struct vop_reclaim_args *ap)
  327 {
  328         struct vnode *vp = ap->a_vp;
  329         struct nfsnode *np = VTONFS(vp);
  330         struct nfsdmap *dp, *dp2;
  331 
  332         if (prtactive && vrefcnt(vp) != 0)
  333                 vprint("nfs_reclaim: pushing active", vp);
  334 
  335         if (np->n_hash.le_prev != NULL)         /* XXX beware */
  336                 LIST_REMOVE(np, n_hash);
  337 
  338         /*
  339          * Free up any directory cookie structures and
  340          * large file handle structures that might be associated with
  341          * this nfs node.
  342          */
  343         if (vp->v_type == VDIR) {
  344                 dp = LIST_FIRST(&np->n_cookies);
  345                 while (dp) {
  346                         dp2 = dp;
  347                         dp = LIST_NEXT(dp, ndm_list);
  348                         FREE((caddr_t)dp2, M_NFSDIROFF);
  349                 }
  350         }
  351         if (np->n_fhsize > NFS_SMALLFH) {
  352                 FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
  353         }
  354 
  355         lockdestroy(&np->n_rslock);
  356 
  357         cache_purge(vp);
  358         uma_zfree(nfsnode_zone, vp->v_data);
  359         vp->v_data = NULL;
  360         return (0);
  361 }

Cache object: 42226c31f414648a16bac1b5a5f958f5


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