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$");
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	}
131143693Sphk	np = uma_zalloc(nfsnode_zone, M_WAITOK | M_ZERO);
13283651Speter
133192578Srwatson	error = getnewvnode("nfs", mntp, &nfs_vnodeops, &nvp);
1343305Sphk	if (error) {
13592783Sjeff		uma_zfree(nfsnode_zone, np);
1361541Srgrimes		return (error);
1371541Srgrimes	}
1381541Srgrimes	vp = nvp;
139192578Srwatson	vp->v_bufobj.bo_ops = &buf_ops_nfs;
1401541Srgrimes	vp->v_data = np;
1411541Srgrimes	np->n_vnode = vp;
142164684Smohans	/*
143164684Smohans	 * Initialize the mutex even if the vnode is going to be a loser.
144164684Smohans	 * This simplifies the logic in reclaim, which can then unconditionally
145164684Smohans	 * destroy the mutex (in the case of the loser, or if hash_insert happened
146164684Smohans	 * to return an error no special casing is needed).
147164684Smohans	 */
148164684Smohans	mtx_init(&np->n_mtx, "NFSnode lock", NULL, MTX_DEF);
149158855Smohans	/*
150158855Smohans	 * NFS supports recursive and shared locking.
151158855Smohans	 */
152211531Sjhb	lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
153176519Sattilio	VN_LOCK_AREC(vp);
154176519Sattilio	VN_LOCK_ASHARE(vp);
155164735Smohans	if (fhsize > NFS_SMALLFH) {
156184205Sdes		np->n_fhp = malloc(fhsize, M_NFSBIGFH, M_WAITOK);
157164735Smohans	} else
158164735Smohans		np->n_fhp = &np->n_fh;
159164735Smohans	bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
160164735Smohans	np->n_fhsize = fhsize;
161167497Stegge	error = insmntque(vp, mntp);
162167497Stegge	if (error != 0) {
163167497Stegge		*npp = NULL;
164167497Stegge		if (np->n_fhsize > NFS_SMALLFH) {
165184205Sdes			free((caddr_t)np->n_fhp, M_NFSBIGFH);
166167497Stegge		}
167167497Stegge		mtx_destroy(&np->n_mtx);
168167497Stegge		uma_zfree(nfsnode_zone, np);
169167497Stegge		return (error);
170167497Stegge	}
171162288Smohans	error = vfs_hash_insert(vp, hash, flags,
172143693Sphk	    td, &nvp, nfs_vncmpf, &ncmp);
173143693Sphk	if (error)
174143693Sphk		return (error);
175143693Sphk	if (nvp != NULL) {
176143693Sphk		*npp = VTONFS(nvp);
177164346Smohans		/* vfs_hash_insert() vput()'s the losing vnode */
178143693Sphk		return (0);
17947750Speter	}
1801541Srgrimes	*npp = np;
1819336Sdfr
1821541Srgrimes	return (0);
1831541Srgrimes}
1841541Srgrimes
185224604Srmacklem/*
186224604Srmacklem * Do the vrele(sp->s_dvp) as a separate task in order to avoid a
187224604Srmacklem * deadlock because of a LOR when vrele() locks the directory vnode.
188224604Srmacklem */
189224604Srmacklemstatic void
190224604Srmacklemnfs_freesillyrename(void *arg, __unused int pending)
191224604Srmacklem{
192224604Srmacklem	struct sillyrename *sp;
193224604Srmacklem
194224604Srmacklem	sp = arg;
195224604Srmacklem	vrele(sp->s_dvp);
196224604Srmacklem	free(sp, M_NFSREQ);
197224604Srmacklem}
198224604Srmacklem
1991549Srgrimesint
20083651Speternfs_inactive(struct vop_inactive_args *ap)
2011541Srgrimes{
20283651Speter	struct nfsnode *np;
20383651Speter	struct sillyrename *sp;
20483366Sjulian	struct thread *td = curthread;	/* XXX */
2051541Srgrimes
2061541Srgrimes	np = VTONFS(ap->a_vp);
207210834Srmacklem	mtx_lock(&np->n_mtx);
20825610Sdfr	if (ap->a_vp->v_type != VDIR) {
2099336Sdfr		sp = np->n_sillyrename;
21099797Sdillon		np->n_sillyrename = NULL;
21125610Sdfr	} else
21299797Sdillon		sp = NULL;
2131541Srgrimes	if (sp) {
214210834Srmacklem		mtx_unlock(&np->n_mtx);
215140731Sphk		(void)nfs_vinvalbuf(ap->a_vp, 0, td, 1);
2161541Srgrimes		/*
2171541Srgrimes		 * Remove the silly file that was rename'd earlier
2181541Srgrimes		 */
219122698Salfred		(sp->s_removeit)(sp);
2201541Srgrimes		crfree(sp->s_cred);
221224604Srmacklem		TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp);
222224604Srmacklem		taskqueue_enqueue(taskqueue_thread, &sp->s_task);
223210834Srmacklem		mtx_lock(&np->n_mtx);
2241541Srgrimes	}
225138469Sps	np->n_flag &= NMODIFIED;
226210834Srmacklem	mtx_unlock(&np->n_mtx);
2271541Srgrimes	return (0);
2281541Srgrimes}
2291541Srgrimes
2301541Srgrimes/*
2311541Srgrimes * Reclaim an nfsnode so that it can be used for other purposes.
2321541Srgrimes */
2331549Srgrimesint
23483651Speternfs_reclaim(struct vop_reclaim_args *ap)
2351541Srgrimes{
23683651Speter	struct vnode *vp = ap->a_vp;
23783651Speter	struct nfsnode *np = VTONFS(vp);
23883651Speter	struct nfsdmap *dp, *dp2;
2391541Srgrimes
240154487Salfred	/*
241180025Sdfr	 * If the NLM is running, give it a chance to abort pending
242180025Sdfr	 * locks.
243180025Sdfr	 */
244180025Sdfr	if (nfs_reclaim_p)
245180025Sdfr		nfs_reclaim_p(ap);
246180025Sdfr
247180025Sdfr	/*
248154487Salfred	 * Destroy the vm object and flush associated pages.
249154487Salfred	 */
250154487Salfred	vnode_destroy_vobject(vp);
251154487Salfred
252143693Sphk	vfs_hash_remove(vp);
2533664Sphk
2541541Srgrimes	/*
2559336Sdfr	 * Free up any directory cookie structures and
2569336Sdfr	 * large file handle structures that might be associated with
2579336Sdfr	 * this nfs node.
2589336Sdfr	 */
2599336Sdfr	if (vp->v_type == VDIR) {
26083651Speter		dp = LIST_FIRST(&np->n_cookies);
2619336Sdfr		while (dp) {
2629336Sdfr			dp2 = dp;
26383651Speter			dp = LIST_NEXT(dp, ndm_list);
264184205Sdes			free((caddr_t)dp2, M_NFSDIROFF);
2659336Sdfr		}
2669336Sdfr	}
267235332Srmacklem	if (np->n_writecred != NULL)
268235332Srmacklem		crfree(np->n_writecred);
2699336Sdfr	if (np->n_fhsize > NFS_SMALLFH) {
270184205Sdes		free((caddr_t)np->n_fhp, M_NFSBIGFH);
2719336Sdfr	}
272158739Smohans	mtx_destroy(&np->n_mtx);
27392783Sjeff	uma_zfree(nfsnode_zone, vp->v_data);
27499797Sdillon	vp->v_data = NULL;
2751541Srgrimes	return (0);
2761541Srgrimes}
277