nfs_node.c revision 211531
1139823Simp/*-
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 4. Neither the name of the University nor the names of its contributors
171541Srgrimes *    may be used to endorse or promote products derived from this software
181541Srgrimes *    without specific prior written permission.
191541Srgrimes *
201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301541Srgrimes * SUCH DAMAGE.
311541Srgrimes *
3222521Sdyson *	@(#)nfs_node.c	8.6 (Berkeley) 5/22/95
331541Srgrimes */
341541Srgrimes
3583651Speter#include <sys/cdefs.h>
3683651Speter__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_node.c 211531 2010-08-20 19:46:50Z jhb $");
3722521Sdyson
381541Srgrimes#include <sys/param.h>
391541Srgrimes#include <sys/systm.h>
4076166Smarkm#include <sys/fnv_hash.h>
4176166Smarkm#include <sys/lock.h>
4276166Smarkm#include <sys/malloc.h>
43192578Srwatson#include <sys/mbuf.h>
441541Srgrimes#include <sys/mount.h>
451541Srgrimes#include <sys/namei.h>
4676166Smarkm#include <sys/proc.h>
4776166Smarkm#include <sys/socket.h>
4876166Smarkm#include <sys/sysctl.h>
491541Srgrimes#include <sys/vnode.h>
501541Srgrimes
5192783Sjeff#include <vm/uma.h>
5232011Sbde
539336Sdfr#include <nfs/nfsproto.h>
5483651Speter#include <nfsclient/nfs.h>
5583651Speter#include <nfsclient/nfsnode.h>
5683651Speter#include <nfsclient/nfsmount.h>
571541Srgrimes
5892783Sjeffstatic uma_zone_t nfsnode_zone;
591541Srgrimes
601541Srgrimes#define TRUE	1
611541Srgrimes#define	FALSE	0
621541Srgrimes
631549Srgrimesvoid
6483651Speternfs_nhinit(void)
651541Srgrimes{
6683651Speter
6792783Sjeff	nfsnode_zone = uma_zcreate("NFSNODE", sizeof(struct nfsnode), NULL,
6892783Sjeff	    NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
691541Srgrimes}
701541Srgrimes
71128111Speadarvoid
72128111Speadarnfs_nhuninit(void)
73128111Speadar{
74128111Speadar	uma_zdestroy(nfsnode_zone);
75128111Speadar}
76128111Speadar
77143693Sphkstruct nfs_vncmp {
78143693Sphk	int	fhsize;
79143693Sphk	void	*fh;
80143693Sphk};
81143693Sphk
82143693Sphkstatic int
83143693Sphknfs_vncmpf(struct vnode *vp, void *arg)
84143693Sphk{
85143693Sphk	struct nfs_vncmp *a;
86143693Sphk	struct nfsnode *np;
87143693Sphk
88143693Sphk	a = arg;
89143693Sphk	np = VTONFS(vp);
90143693Sphk	return (bcmp(a->fh, np->n_fhp, a->fhsize));
91143693Sphk}
92143693Sphk
93128111Speadar/*
941541Srgrimes * Look up a vnode/nfsnode by file handle.
951541Srgrimes * Callers must check for mount points!!
961541Srgrimes * In all cases, a pointer to a
971541Srgrimes * nfsnode structure is returned.
981541Srgrimes */
991549Srgrimesint
100162288Smohansnfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int flags)
1011541Srgrimes{
10283366Sjulian	struct thread *td = curthread;	/* XXX */
103143693Sphk	struct nfsnode *np;
10483651Speter	struct vnode *vp;
1051541Srgrimes	struct vnode *nvp;
1061541Srgrimes	int error;
107143693Sphk	u_int hash;
10855431Sdillon	struct nfsmount *nmp;
109143693Sphk	struct nfs_vncmp ncmp;
1101541Srgrimes
11155431Sdillon	nmp = VFSTONFS(mntp);
112143693Sphk	*npp = NULL;
113143693Sphk
114143693Sphk	hash = fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT);
115143693Sphk	ncmp.fhsize = fhsize;
116143693Sphk	ncmp.fh = fhp;
117143693Sphk
118162288Smohans	error = vfs_hash_get(mntp, hash, flags,
119143693Sphk	    td, &nvp, nfs_vncmpf, &ncmp);
120143693Sphk	if (error)
121143693Sphk		return (error);
122143693Sphk	if (nvp != NULL) {
123143693Sphk		*npp = VTONFS(nvp);
124143693Sphk		return (0);
1251541Srgrimes	}
12616312Sdg
12716312Sdg	/*
12836329Speter	 * Allocate before getnewvnode since doing so afterward
12916312Sdg	 * might cause a bogus v_data pointer to get dereferenced
13036329Speter	 * elsewhere if zalloc should block.
13116312Sdg	 */
132143693Sphk	np = uma_zalloc(nfsnode_zone, M_WAITOK | M_ZERO);
13383651Speter
134192578Srwatson	error = getnewvnode("nfs", mntp, &nfs_vnodeops, &nvp);
1353305Sphk	if (error) {
13692783Sjeff		uma_zfree(nfsnode_zone, np);
1371541Srgrimes		return (error);
1381541Srgrimes	}
1391541Srgrimes	vp = nvp;
140192578Srwatson	vp->v_bufobj.bo_ops = &buf_ops_nfs;
1411541Srgrimes	vp->v_data = np;
1421541Srgrimes	np->n_vnode = vp;
143164684Smohans	/*
144164684Smohans	 * Initialize the mutex even if the vnode is going to be a loser.
145164684Smohans	 * This simplifies the logic in reclaim, which can then unconditionally
146164684Smohans	 * destroy the mutex (in the case of the loser, or if hash_insert happened
147164684Smohans	 * to return an error no special casing is needed).
148164684Smohans	 */
149164684Smohans	mtx_init(&np->n_mtx, "NFSnode lock", NULL, MTX_DEF);
150158855Smohans	/*
151158855Smohans	 * NFS supports recursive and shared locking.
152158855Smohans	 */
153211531Sjhb	lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
154176519Sattilio	VN_LOCK_AREC(vp);
155176519Sattilio	VN_LOCK_ASHARE(vp);
156164735Smohans	if (fhsize > NFS_SMALLFH) {
157184205Sdes		np->n_fhp = malloc(fhsize, M_NFSBIGFH, M_WAITOK);
158164735Smohans	} else
159164735Smohans		np->n_fhp = &np->n_fh;
160164735Smohans	bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
161164735Smohans	np->n_fhsize = fhsize;
162167497Stegge	error = insmntque(vp, mntp);
163167497Stegge	if (error != 0) {
164167497Stegge		*npp = NULL;
165167497Stegge		if (np->n_fhsize > NFS_SMALLFH) {
166184205Sdes			free((caddr_t)np->n_fhp, M_NFSBIGFH);
167167497Stegge		}
168167497Stegge		mtx_destroy(&np->n_mtx);
169167497Stegge		uma_zfree(nfsnode_zone, np);
170167497Stegge		return (error);
171167497Stegge	}
172162288Smohans	error = vfs_hash_insert(vp, hash, flags,
173143693Sphk	    td, &nvp, nfs_vncmpf, &ncmp);
174143693Sphk	if (error)
175143693Sphk		return (error);
176143693Sphk	if (nvp != NULL) {
177143693Sphk		*npp = VTONFS(nvp);
178164346Smohans		/* vfs_hash_insert() vput()'s the losing vnode */
179143693Sphk		return (0);
18047750Speter	}
1811541Srgrimes	*npp = np;
1829336Sdfr
1831541Srgrimes	return (0);
1841541Srgrimes}
1851541Srgrimes
1861549Srgrimesint
18783651Speternfs_inactive(struct vop_inactive_args *ap)
1881541Srgrimes{
18983651Speter	struct nfsnode *np;
19083651Speter	struct sillyrename *sp;
19183366Sjulian	struct thread *td = curthread;	/* XXX */
1921541Srgrimes
1931541Srgrimes	np = VTONFS(ap->a_vp);
194103939Sjeff	if (prtactive && vrefcnt(ap->a_vp) != 0)
1951541Srgrimes		vprint("nfs_inactive: pushing active", ap->a_vp);
196210834Srmacklem	mtx_lock(&np->n_mtx);
19725610Sdfr	if (ap->a_vp->v_type != VDIR) {
1989336Sdfr		sp = np->n_sillyrename;
19999797Sdillon		np->n_sillyrename = NULL;
20025610Sdfr	} else
20199797Sdillon		sp = NULL;
2021541Srgrimes	if (sp) {
203210834Srmacklem		mtx_unlock(&np->n_mtx);
204140731Sphk		(void)nfs_vinvalbuf(ap->a_vp, 0, td, 1);
2051541Srgrimes		/*
2061541Srgrimes		 * Remove the silly file that was rename'd earlier
2071541Srgrimes		 */
208122698Salfred		(sp->s_removeit)(sp);
2091541Srgrimes		crfree(sp->s_cred);
2101541Srgrimes		vrele(sp->s_dvp);
211184205Sdes		free((caddr_t)sp, M_NFSREQ);
212210834Srmacklem		mtx_lock(&np->n_mtx);
2131541Srgrimes	}
214138469Sps	np->n_flag &= NMODIFIED;
215210834Srmacklem	mtx_unlock(&np->n_mtx);
2161541Srgrimes	return (0);
2171541Srgrimes}
2181541Srgrimes
2191541Srgrimes/*
2201541Srgrimes * Reclaim an nfsnode so that it can be used for other purposes.
2211541Srgrimes */
2221549Srgrimesint
22383651Speternfs_reclaim(struct vop_reclaim_args *ap)
2241541Srgrimes{
22583651Speter	struct vnode *vp = ap->a_vp;
22683651Speter	struct nfsnode *np = VTONFS(vp);
22783651Speter	struct nfsdmap *dp, *dp2;
2281541Srgrimes
229103939Sjeff	if (prtactive && vrefcnt(vp) != 0)
2301541Srgrimes		vprint("nfs_reclaim: pushing active", vp);
2311541Srgrimes
232154487Salfred	/*
233180025Sdfr	 * If the NLM is running, give it a chance to abort pending
234180025Sdfr	 * locks.
235180025Sdfr	 */
236180025Sdfr	if (nfs_reclaim_p)
237180025Sdfr		nfs_reclaim_p(ap);
238180025Sdfr
239180025Sdfr	/*
240154487Salfred	 * Destroy the vm object and flush associated pages.
241154487Salfred	 */
242154487Salfred	vnode_destroy_vobject(vp);
243154487Salfred
244143693Sphk	vfs_hash_remove(vp);
2453664Sphk
2461541Srgrimes	/*
2479336Sdfr	 * Free up any directory cookie structures and
2489336Sdfr	 * large file handle structures that might be associated with
2499336Sdfr	 * this nfs node.
2509336Sdfr	 */
2519336Sdfr	if (vp->v_type == VDIR) {
25283651Speter		dp = LIST_FIRST(&np->n_cookies);
2539336Sdfr		while (dp) {
2549336Sdfr			dp2 = dp;
25583651Speter			dp = LIST_NEXT(dp, ndm_list);
256184205Sdes			free((caddr_t)dp2, M_NFSDIROFF);
2579336Sdfr		}
2589336Sdfr	}
2599336Sdfr	if (np->n_fhsize > NFS_SMALLFH) {
260184205Sdes		free((caddr_t)np->n_fhp, M_NFSBIGFH);
2619336Sdfr	}
262158739Smohans	mtx_destroy(&np->n_mtx);
26392783Sjeff	uma_zfree(nfsnode_zone, vp->v_data);
26499797Sdillon	vp->v_data = NULL;
2651541Srgrimes	return (0);
2661541Srgrimes}
267