nfs_node.c revision 224604
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 224604 2011-08-02 11:24:42Z rmacklem $");
3722521Sdyson
381541Srgrimes#include <sys/param.h>
391541Srgrimes#include <sys/systm.h>
40214048Srmacklem#include <sys/fcntl.h>
4176166Smarkm#include <sys/fnv_hash.h>
4276166Smarkm#include <sys/lock.h>
4376166Smarkm#include <sys/malloc.h>
44192578Srwatson#include <sys/mbuf.h>
451541Srgrimes#include <sys/mount.h>
461541Srgrimes#include <sys/namei.h>
4776166Smarkm#include <sys/proc.h>
4876166Smarkm#include <sys/socket.h>
4976166Smarkm#include <sys/sysctl.h>
50224604Srmacklem#include <sys/taskqueue.h>
511541Srgrimes#include <sys/vnode.h>
521541Srgrimes
5392783Sjeff#include <vm/uma.h>
5432011Sbde
559336Sdfr#include <nfs/nfsproto.h>
56214048Srmacklem#include <nfs/nfs_lock.h>
5783651Speter#include <nfsclient/nfs.h>
5883651Speter#include <nfsclient/nfsnode.h>
5983651Speter#include <nfsclient/nfsmount.h>
601541Srgrimes
6192783Sjeffstatic uma_zone_t nfsnode_zone;
621541Srgrimes
63224604Srmacklemstatic void	nfs_freesillyrename(void *arg, __unused int pending);
64224604Srmacklem
651541Srgrimes#define TRUE	1
661541Srgrimes#define	FALSE	0
671541Srgrimes
681549Srgrimesvoid
6983651Speternfs_nhinit(void)
701541Srgrimes{
7183651Speter
7292783Sjeff	nfsnode_zone = uma_zcreate("NFSNODE", sizeof(struct nfsnode), NULL,
7392783Sjeff	    NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
741541Srgrimes}
751541Srgrimes
76128111Speadarvoid
77128111Speadarnfs_nhuninit(void)
78128111Speadar{
79128111Speadar	uma_zdestroy(nfsnode_zone);
80128111Speadar}
81128111Speadar
82143693Sphkstruct nfs_vncmp {
83143693Sphk	int	fhsize;
84143693Sphk	void	*fh;
85143693Sphk};
86143693Sphk
87143693Sphkstatic int
88143693Sphknfs_vncmpf(struct vnode *vp, void *arg)
89143693Sphk{
90143693Sphk	struct nfs_vncmp *a;
91143693Sphk	struct nfsnode *np;
92143693Sphk
93143693Sphk	a = arg;
94143693Sphk	np = VTONFS(vp);
95143693Sphk	return (bcmp(a->fh, np->n_fhp, a->fhsize));
96143693Sphk}
97143693Sphk
98128111Speadar/*
991541Srgrimes * Look up a vnode/nfsnode by file handle.
1001541Srgrimes * Callers must check for mount points!!
1011541Srgrimes * In all cases, a pointer to a
1021541Srgrimes * nfsnode structure is returned.
1031541Srgrimes */
1041549Srgrimesint
105162288Smohansnfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int flags)
1061541Srgrimes{
10783366Sjulian	struct thread *td = curthread;	/* XXX */
108143693Sphk	struct nfsnode *np;
10983651Speter	struct vnode *vp;
1101541Srgrimes	struct vnode *nvp;
1111541Srgrimes	int error;
112143693Sphk	u_int hash;
11355431Sdillon	struct nfsmount *nmp;
114143693Sphk	struct nfs_vncmp ncmp;
1151541Srgrimes
11655431Sdillon	nmp = VFSTONFS(mntp);
117143693Sphk	*npp = NULL;
118143693Sphk
119143693Sphk	hash = fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT);
120143693Sphk	ncmp.fhsize = fhsize;
121143693Sphk	ncmp.fh = fhp;
122143693Sphk
123162288Smohans	error = vfs_hash_get(mntp, hash, flags,
124143693Sphk	    td, &nvp, nfs_vncmpf, &ncmp);
125143693Sphk	if (error)
126143693Sphk		return (error);
127143693Sphk	if (nvp != NULL) {
128143693Sphk		*npp = VTONFS(nvp);
129143693Sphk		return (0);
1301541Srgrimes	}
13116312Sdg
13216312Sdg	/*
13336329Speter	 * Allocate before getnewvnode since doing so afterward
13416312Sdg	 * might cause a bogus v_data pointer to get dereferenced
13536329Speter	 * elsewhere if zalloc should block.
13616312Sdg	 */
137143693Sphk	np = uma_zalloc(nfsnode_zone, M_WAITOK | M_ZERO);
13883651Speter
139192578Srwatson	error = getnewvnode("nfs", mntp, &nfs_vnodeops, &nvp);
1403305Sphk	if (error) {
14192783Sjeff		uma_zfree(nfsnode_zone, np);
1421541Srgrimes		return (error);
1431541Srgrimes	}
1441541Srgrimes	vp = nvp;
145192578Srwatson	vp->v_bufobj.bo_ops = &buf_ops_nfs;
1461541Srgrimes	vp->v_data = np;
1471541Srgrimes	np->n_vnode = vp;
148164684Smohans	/*
149164684Smohans	 * Initialize the mutex even if the vnode is going to be a loser.
150164684Smohans	 * This simplifies the logic in reclaim, which can then unconditionally
151164684Smohans	 * destroy the mutex (in the case of the loser, or if hash_insert happened
152164684Smohans	 * to return an error no special casing is needed).
153164684Smohans	 */
154164684Smohans	mtx_init(&np->n_mtx, "NFSnode lock", NULL, MTX_DEF);
155158855Smohans	/*
156158855Smohans	 * NFS supports recursive and shared locking.
157158855Smohans	 */
158211531Sjhb	lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
159176519Sattilio	VN_LOCK_AREC(vp);
160176519Sattilio	VN_LOCK_ASHARE(vp);
161164735Smohans	if (fhsize > NFS_SMALLFH) {
162184205Sdes		np->n_fhp = malloc(fhsize, M_NFSBIGFH, M_WAITOK);
163164735Smohans	} else
164164735Smohans		np->n_fhp = &np->n_fh;
165164735Smohans	bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
166164735Smohans	np->n_fhsize = fhsize;
167167497Stegge	error = insmntque(vp, mntp);
168167497Stegge	if (error != 0) {
169167497Stegge		*npp = NULL;
170167497Stegge		if (np->n_fhsize > NFS_SMALLFH) {
171184205Sdes			free((caddr_t)np->n_fhp, M_NFSBIGFH);
172167497Stegge		}
173167497Stegge		mtx_destroy(&np->n_mtx);
174167497Stegge		uma_zfree(nfsnode_zone, np);
175167497Stegge		return (error);
176167497Stegge	}
177162288Smohans	error = vfs_hash_insert(vp, hash, flags,
178143693Sphk	    td, &nvp, nfs_vncmpf, &ncmp);
179143693Sphk	if (error)
180143693Sphk		return (error);
181143693Sphk	if (nvp != NULL) {
182143693Sphk		*npp = VTONFS(nvp);
183164346Smohans		/* vfs_hash_insert() vput()'s the losing vnode */
184143693Sphk		return (0);
18547750Speter	}
1861541Srgrimes	*npp = np;
1879336Sdfr
1881541Srgrimes	return (0);
1891541Srgrimes}
1901541Srgrimes
191224604Srmacklem/*
192224604Srmacklem * Do the vrele(sp->s_dvp) as a separate task in order to avoid a
193224604Srmacklem * deadlock because of a LOR when vrele() locks the directory vnode.
194224604Srmacklem */
195224604Srmacklemstatic void
196224604Srmacklemnfs_freesillyrename(void *arg, __unused int pending)
197224604Srmacklem{
198224604Srmacklem	struct sillyrename *sp;
199224604Srmacklem
200224604Srmacklem	sp = arg;
201224604Srmacklem	vrele(sp->s_dvp);
202224604Srmacklem	free(sp, M_NFSREQ);
203224604Srmacklem}
204224604Srmacklem
2051549Srgrimesint
20683651Speternfs_inactive(struct vop_inactive_args *ap)
2071541Srgrimes{
20883651Speter	struct nfsnode *np;
20983651Speter	struct sillyrename *sp;
21083366Sjulian	struct thread *td = curthread;	/* XXX */
2111541Srgrimes
2121541Srgrimes	np = VTONFS(ap->a_vp);
213210834Srmacklem	mtx_lock(&np->n_mtx);
21425610Sdfr	if (ap->a_vp->v_type != VDIR) {
2159336Sdfr		sp = np->n_sillyrename;
21699797Sdillon		np->n_sillyrename = NULL;
21725610Sdfr	} else
21899797Sdillon		sp = NULL;
2191541Srgrimes	if (sp) {
220210834Srmacklem		mtx_unlock(&np->n_mtx);
221140731Sphk		(void)nfs_vinvalbuf(ap->a_vp, 0, td, 1);
2221541Srgrimes		/*
2231541Srgrimes		 * Remove the silly file that was rename'd earlier
2241541Srgrimes		 */
225122698Salfred		(sp->s_removeit)(sp);
2261541Srgrimes		crfree(sp->s_cred);
227224604Srmacklem		TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp);
228224604Srmacklem		taskqueue_enqueue(taskqueue_thread, &sp->s_task);
229210834Srmacklem		mtx_lock(&np->n_mtx);
2301541Srgrimes	}
231138469Sps	np->n_flag &= NMODIFIED;
232210834Srmacklem	mtx_unlock(&np->n_mtx);
2331541Srgrimes	return (0);
2341541Srgrimes}
2351541Srgrimes
2361541Srgrimes/*
2371541Srgrimes * Reclaim an nfsnode so that it can be used for other purposes.
2381541Srgrimes */
2391549Srgrimesint
24083651Speternfs_reclaim(struct vop_reclaim_args *ap)
2411541Srgrimes{
24283651Speter	struct vnode *vp = ap->a_vp;
24383651Speter	struct nfsnode *np = VTONFS(vp);
24483651Speter	struct nfsdmap *dp, *dp2;
2451541Srgrimes
246154487Salfred	/*
247180025Sdfr	 * If the NLM is running, give it a chance to abort pending
248180025Sdfr	 * locks.
249180025Sdfr	 */
250180025Sdfr	if (nfs_reclaim_p)
251180025Sdfr		nfs_reclaim_p(ap);
252180025Sdfr
253180025Sdfr	/*
254154487Salfred	 * Destroy the vm object and flush associated pages.
255154487Salfred	 */
256154487Salfred	vnode_destroy_vobject(vp);
257154487Salfred
258143693Sphk	vfs_hash_remove(vp);
2593664Sphk
2601541Srgrimes	/*
2619336Sdfr	 * Free up any directory cookie structures and
2629336Sdfr	 * large file handle structures that might be associated with
2639336Sdfr	 * this nfs node.
2649336Sdfr	 */
2659336Sdfr	if (vp->v_type == VDIR) {
26683651Speter		dp = LIST_FIRST(&np->n_cookies);
2679336Sdfr		while (dp) {
2689336Sdfr			dp2 = dp;
26983651Speter			dp = LIST_NEXT(dp, ndm_list);
270184205Sdes			free((caddr_t)dp2, M_NFSDIROFF);
2719336Sdfr		}
2729336Sdfr	}
2739336Sdfr	if (np->n_fhsize > NFS_SMALLFH) {
274184205Sdes		free((caddr_t)np->n_fhp, M_NFSBIGFH);
2759336Sdfr	}
276158739Smohans	mtx_destroy(&np->n_mtx);
27792783Sjeff	uma_zfree(nfsnode_zone, vp->v_data);
27899797Sdillon	vp->v_data = NULL;
2791541Srgrimes	return (0);
2801541Srgrimes}
281