/* $OpenBSD: nfs_node.c,v 1.36 2007/09/20 12:54:31 thib Exp $ */ /* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 */ #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/mount.h> #include <sys/namei.h> #include <sys/vnode.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/pool.h> #include <sys/hash.h> #include <sys/rwlock.h> #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> #include <nfs/nfs.h> #include <nfs/nfsnode.h> #include <nfs/nfsmount.h> #include <nfs/nfs_var.h> LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; u_long nfsnodehash; struct rwlock nfs_hashlock = RWLOCK_INITIALIZER("nfshshlk"); struct pool nfs_node_pool; extern int prtactive; #define TRUE 1 #define FALSE 0 #define nfs_hash(x,y) hash32_buf((x), (y), HASHINIT) /* * Initialize hash links for nfsnodes * and build nfsnode free list. */ void nfs_nhinit() { nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, M_WAITOK, &nfsnodehash); pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0, "nfsnodepl", &pool_allocator_nointr); } /* * Look up a vnode/nfsnode by file handle. * Callers must check for mount points!! * In all cases, a pointer to a * nfsnode structure is returned. */ int nfs_nget(mntp, fhp, fhsize, npp) struct mount *mntp; nfsfh_t *fhp; int fhsize; struct nfsnode **npp; { struct proc *p = curproc; /* XXX */ struct nfsnode *np; struct nfsnodehashhead *nhpp; struct vnode *vp; extern int (**nfsv2_vnodeop_p)(void *); struct vnode *nvp; int error; nhpp = NFSNOHASH(nfs_hash(fhp, fhsize)); loop: for (np = LIST_FIRST(nhpp); np != NULL; np = LIST_NEXT(np, n_hash)) { if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) continue; vp = NFSTOV(np); if (vget(vp, LK_EXCLUSIVE, p)) goto loop; *npp = np; return(0); } if (rw_enter(&nfs_hashlock, RW_WRITE|RW_SLEEPFAIL)) goto loop; error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); if (error) { *npp = 0; rw_exit(&nfs_hashlock); return (error); } vp = nvp; np = pool_get(&nfs_node_pool, PR_WAITOK); bzero((caddr_t)np, sizeof *np); vp->v_data = np; np->n_vnode = vp; rw_init(&np->n_commitlock, "nfs_commitlk"); /* * Are we getting the root? If so, make sure the vnode flags * are correct */ { struct nfsmount *nmp = VFSTONFS(mntp); if ((fhsize == nmp->nm_fhsize) && !bcmp(fhp, nmp->nm_fh, fhsize)) { if (vp->v_type == VNON) vp->v_type = VDIR; vp->v_flag |= VROOT; } } LIST_INSERT_HEAD(nhpp, np, n_hash); if (fhsize > NFS_SMALLFH) { np->n_fhp = malloc(fhsize, M_NFSBIGFH, M_WAITOK); } else np->n_fhp = &np->n_fh; bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); np->n_fhsize = fhsize; rw_exit(&nfs_hashlock); *npp = np; return (0); } int nfs_inactive(v) void *v; { struct vop_inactive_args *ap = v; struct nfsnode *np; struct sillyrename *sp; struct proc *p = curproc; /* XXX */ np = VTONFS(ap->a_vp); #ifdef DIAGNOSTIC if (prtactive && ap->a_vp->v_usecount != 0) vprint("nfs_inactive: pushing active", ap->a_vp); #endif if (ap->a_vp->v_type != VDIR) { sp = np->n_sillyrename; np->n_sillyrename = (struct sillyrename *)0; } else sp = (struct sillyrename *)0; if (sp) { /* * Remove the silly file that was rename'd earlier */ (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1); nfs_removeit(sp); crfree(sp->s_cred); vrele(sp->s_dvp); free(sp, M_NFSREQ); } np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT); VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } /* * Reclaim an nfsnode so that it can be used for other purposes. */ int nfs_reclaim(v) void *v; { struct vop_reclaim_args *ap = v; struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct nfsdmap *dp, *dp2; #ifdef DIAGNOSTIC if (prtactive && vp->v_usecount != 0) vprint("nfs_reclaim: pushing active", vp); #endif if (np->n_hash.le_prev != NULL) LIST_REMOVE(np, n_hash); /* * Free up any directory cookie structures and * large file handle structures that might be associated with * this nfs node. */ if (vp->v_type == VDIR) { dp = LIST_FIRST(&np->n_cookies); while (dp) { dp2 = dp; dp = LIST_NEXT(dp, ndm_list); free(dp2, M_NFSDIROFF); } } if (np->n_fhsize > NFS_SMALLFH) { free(np->n_fhp, M_NFSBIGFH); } if (np->n_rcred) crfree(np->n_rcred); if (np->n_wcred) crfree(np->n_wcred); cache_purge(vp); pool_put(&nfs_node_pool, vp->v_data); vp->v_data = NULL; return (0); }