nfs_clnode.c revision 230605
190075Sobrien/*-
290075Sobrien * Copyright (c) 1989, 1993
3169689Skan *	The Regents of the University of California.  All rights reserved.
490075Sobrien *
590075Sobrien * This code is derived from software contributed to Berkeley by
690075Sobrien * Rick Macklem at The University of Guelph.
790075Sobrien *
890075Sobrien * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1190075Sobrien * 1. Redistributions of source code must retain the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1690075Sobrien * 4. Neither the name of the University nor the names of its contributors
1790075Sobrien *    may be used to endorse or promote products derived from this software
1890075Sobrien *    without specific prior written permission.
19169689Skan *
20169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2190075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2290075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2390075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2490075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2590075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2790075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2890075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30132718Skan * SUCH DAMAGE.
31132718Skan *
32132718Skan *	from nfs_node.c	8.6 (Berkeley) 5/22/95
33132718Skan */
34132718Skan
3590075Sobrien#include <sys/cdefs.h>
3690075Sobrien__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clnode.c 230605 2012-01-27 02:46:12Z rmacklem $");
3790075Sobrien
38132718Skan#include "opt_kdtrace.h"
3990075Sobrien
4090075Sobrien#include <sys/param.h>
4190075Sobrien#include <sys/systm.h>
42132718Skan#include <sys/fcntl.h>
43132718Skan#include <sys/lock.h>
4490075Sobrien#include <sys/malloc.h>
4590075Sobrien#include <sys/mount.h>
4690075Sobrien#include <sys/namei.h>
4790075Sobrien#include <sys/proc.h>
4890075Sobrien#include <sys/socket.h>
4990075Sobrien#include <sys/sysctl.h>
5090075Sobrien#include <sys/taskqueue.h>
5190075Sobrien#include <sys/vnode.h>
5290075Sobrien
5390075Sobrien#include <vm/uma.h>
5490075Sobrien
5590075Sobrien#include <fs/nfs/nfsport.h>
56117395Skan#include <fs/nfsclient/nfsnode.h>
57132718Skan#include <fs/nfsclient/nfsmount.h>
58132718Skan#include <fs/nfsclient/nfs.h>
59169689Skan#include <fs/nfsclient/nfs_kdtrace.h>
60169689Skan
61169689Skan#include <nfs/nfs_lock.h>
62169689Skan
6390075Sobrienextern struct vop_vector newnfs_vnodeops;
64132718Skanextern struct buf_ops buf_ops_newnfs;
65132718SkanMALLOC_DECLARE(M_NEWNFSREQ);
66132718Skan
67132718Skanuma_zone_t newnfsnode_zone;
68169689Skan
69132718Skanstatic void	nfs_freesillyrename(void *arg, __unused int pending);
70169689Skan
71169689Skanvoid
72132718Skanncl_nhinit(void)
73132718Skan{
74132718Skan
75132718Skan	newnfsnode_zone = uma_zcreate("NCLNODE", sizeof(struct nfsnode), NULL,
76169689Skan	    NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
77169689Skan}
78169689Skan
79132718Skanvoid
80169689Skanncl_nhuninit(void)
8190075Sobrien{
8290075Sobrien	uma_zdestroy(newnfsnode_zone);
8390075Sobrien}
8490075Sobrien
8590075Sobrien/*
86132718Skan * ONLY USED FOR THE ROOT DIRECTORY. nfscl_nget() does the rest. If this
8790075Sobrien * function is going to be used to get Regular Files, code must be added
8890075Sobrien * to fill in the "struct nfsv4node".
89169689Skan * Look up a vnode/nfsnode by file handle.
9090075Sobrien * Callers must check for mount points!!
9190075Sobrien * In all cases, a pointer to a
9290075Sobrien * nfsnode structure is returned.
9390075Sobrien */
9490075Sobrienint
95132718Skanncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp,
9690075Sobrien    int lkflags)
9790075Sobrien{
9890075Sobrien	struct thread *td = curthread;	/* XXX */
9990075Sobrien	struct nfsnode *np;
100169689Skan	struct vnode *vp;
10190075Sobrien	struct vnode *nvp;
10290075Sobrien	int error;
10390075Sobrien	u_int hash;
10490075Sobrien	struct nfsmount *nmp;
10590075Sobrien	struct nfsfh *nfhp;
106132718Skan
10790075Sobrien	nmp = VFSTONFS(mntp);
10890075Sobrien	*npp = NULL;
10990075Sobrien
11090075Sobrien	hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT);
11190075Sobrien
112169689Skan	MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
11390075Sobrien	    M_NFSFH, M_WAITOK);
11490075Sobrien	bcopy(fhp, &nfhp->nfh_fh[0], fhsize);
115169689Skan	nfhp->nfh_len = fhsize;
116169689Skan	error = vfs_hash_get(mntp, hash, lkflags,
11790075Sobrien	    td, &nvp, newnfs_vncmpf, nfhp);
11890075Sobrien	FREE(nfhp, M_NFSFH);
11990075Sobrien	if (error)
12090075Sobrien		return (error);
12190075Sobrien	if (nvp != NULL) {
12290075Sobrien		*npp = VTONFS(nvp);
12390075Sobrien		return (0);
124169689Skan	}
12590075Sobrien
12690075Sobrien	/*
12790075Sobrien	 * Allocate before getnewvnode since doing so afterward
12890075Sobrien	 * might cause a bogus v_data pointer to get dereferenced
12990075Sobrien	 * elsewhere if zalloc should block.
13090075Sobrien	 */
13190075Sobrien	np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
13290075Sobrien
133169689Skan	error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
13490075Sobrien	if (error) {
13590075Sobrien		uma_zfree(newnfsnode_zone, np);
13690075Sobrien		return (error);
13790075Sobrien	}
13890075Sobrien	vp = nvp;
13990075Sobrien	KASSERT(vp->v_bufobj.bo_bsize != 0, ("ncl_nget: bo_bsize == 0"));
140169689Skan	vp->v_bufobj.bo_ops = &buf_ops_newnfs;
14190075Sobrien	vp->v_data = np;
142169689Skan	np->n_vnode = vp;
14390075Sobrien	/*
14490075Sobrien	 * Initialize the mutex even if the vnode is going to be a loser.
14590075Sobrien	 * This simplifies the logic in reclaim, which can then unconditionally
146132718Skan	 * destroy the mutex (in the case of the loser, or if hash_insert
147132718Skan	 * happened to return an error no special casing is needed).
148132718Skan	 */
149169689Skan	mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK);
150132718Skan	/*
151132718Skan	 * NFS supports recursive and shared locking.
152132718Skan	 */
153132718Skan	lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
154132718Skan	VN_LOCK_AREC(vp);
15590075Sobrien	VN_LOCK_ASHARE(vp);
156169689Skan	/*
15790075Sobrien	 * Are we getting the root? If so, make sure the vnode flags
15890075Sobrien	 * are correct
15990075Sobrien	 */
16090075Sobrien	if ((fhsize == nmp->nm_fhsize) &&
16190075Sobrien	    !bcmp(fhp, nmp->nm_fh, fhsize)) {
16290075Sobrien		if (vp->v_type == VNON)
16390075Sobrien			vp->v_type = VDIR;
16490075Sobrien		vp->v_vflag |= VV_ROOT;
16590075Sobrien	}
16690075Sobrien
16790075Sobrien	MALLOC(np->n_fhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
16890075Sobrien	    M_NFSFH, M_WAITOK);
16990075Sobrien	bcopy(fhp, np->n_fhp->nfh_fh, fhsize);
17090075Sobrien	np->n_fhp->nfh_len = fhsize;
17190075Sobrien	error = insmntque(vp, mntp);
172169689Skan	if (error != 0) {
17390075Sobrien		*npp = NULL;
17490075Sobrien		FREE((caddr_t)np->n_fhp, M_NFSFH);
17590075Sobrien		mtx_destroy(&np->n_mtx);
17690075Sobrien		uma_zfree(newnfsnode_zone, np);
17790075Sobrien		return (error);
17890075Sobrien	}
17990075Sobrien	error = vfs_hash_insert(vp, hash, lkflags,
180117395Skan	    td, &nvp, newnfs_vncmpf, np->n_fhp);
181117395Skan	if (error)
182132718Skan		return (error);
183117395Skan	if (nvp != NULL) {
184117395Skan		*npp = VTONFS(nvp);
185117395Skan		/* vfs_hash_insert() vput()'s the losing vnode */
186117395Skan		return (0);
187117395Skan	}
188117395Skan	*npp = np;
189132718Skan
190117395Skan	return (0);
191117395Skan}
192117395Skan
193117395Skan/*
194117395Skan * Do the vrele(sp->s_dvp) as a separate task in order to avoid a
195117395Skan * deadlock because of a LOR when vrele() locks the directory vnode.
196117395Skan */
19790075Sobrienstatic void
19890075Sobriennfs_freesillyrename(void *arg, __unused int pending)
19990075Sobrien{
20090075Sobrien	struct sillyrename *sp;
201132718Skan
20290075Sobrien	sp = arg;
20390075Sobrien	vrele(sp->s_dvp);
20490075Sobrien	free(sp, M_NEWNFSREQ);
20590075Sobrien}
20690075Sobrien
20790075Sobrienint
20890075Sobrienncl_inactive(struct vop_inactive_args *ap)
20990075Sobrien{
21090075Sobrien	struct nfsnode *np;
211169689Skan	struct sillyrename *sp;
21290075Sobrien	struct vnode *vp = ap->a_vp;
21390075Sobrien
21490075Sobrien	np = VTONFS(vp);
21590075Sobrien
21690075Sobrien	if (NFS_ISV4(vp) && vp->v_type == VREG) {
21790075Sobrien		/*
21890075Sobrien		 * Since mmap()'d files do I/O after VOP_CLOSE(), the NFSv4
21990075Sobrien		 * Close operations are delayed until now. Any dirty buffers
22090075Sobrien		 * must be flushed before the close, so that the stateid is
221117395Skan		 * available for the writes.
222117395Skan		 */
223117395Skan		(void) ncl_flush(vp, MNT_WAIT, NULL, ap->a_td, 1, 0);
224132718Skan		(void) nfsrpc_close(vp, 1, ap->a_td);
225117395Skan	}
226117395Skan
227117395Skan	mtx_lock(&np->n_mtx);
228117395Skan	if (vp->v_type != VDIR) {
229117395Skan		sp = np->n_sillyrename;
230132718Skan		np->n_sillyrename = NULL;
231117395Skan	} else
232117395Skan		sp = NULL;
233117395Skan	if (sp) {
234117395Skan		mtx_unlock(&np->n_mtx);
235117395Skan		(void) ncl_vinvalbuf(vp, 0, ap->a_td, 1);
23690075Sobrien		/*
23790075Sobrien		 * Remove the silly file that was rename'd earlier
23890075Sobrien		 */
23990075Sobrien		ncl_removeit(sp, vp);
24090075Sobrien		crfree(sp->s_cred);
24190075Sobrien		TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp);
242117395Skan		taskqueue_enqueue(taskqueue_thread, &sp->s_task);
243117395Skan		mtx_lock(&np->n_mtx);
24490075Sobrien	}
24590075Sobrien	np->n_flag &= NMODIFIED;
246132718Skan	mtx_unlock(&np->n_mtx);
24790075Sobrien	return (0);
24890075Sobrien}
24990075Sobrien
25090075Sobrien/*
25190075Sobrien * Reclaim an nfsnode so that it can be used for other purposes.
25290075Sobrien */
25390075Sobrienint
25490075Sobrienncl_reclaim(struct vop_reclaim_args *ap)
25590075Sobrien{
25690075Sobrien	struct vnode *vp = ap->a_vp;
25790075Sobrien	struct nfsnode *np = VTONFS(vp);
258169689Skan	struct nfsdmap *dp, *dp2;
25990075Sobrien
26090075Sobrien	if (NFS_ISV4(vp) && vp->v_type == VREG)
26190075Sobrien		/*
26290075Sobrien		 * Since mmap()'d files do I/O after VOP_CLOSE(), the NFSv4
26390075Sobrien		 * Close operations are delayed until ncl_inactive().
26490075Sobrien		 * However, since VOP_INACTIVE() is not guaranteed to be
26590075Sobrien		 * called, we need to do it again here.
26690075Sobrien		 */
267117395Skan		(void) nfsrpc_close(vp, 1, ap->a_td);
26890075Sobrien
26990075Sobrien	/*
27090075Sobrien	 * If the NLM is running, give it a chance to abort pending
27190075Sobrien	 * locks.
27290075Sobrien	 */
27390075Sobrien	if (nfs_reclaim_p != NULL)
27490075Sobrien		nfs_reclaim_p(ap);
275169689Skan
27690075Sobrien	/*
27790075Sobrien	 * Destroy the vm object and flush associated pages.
27890075Sobrien	 */
279169689Skan	vnode_destroy_vobject(vp);
28090075Sobrien
28190075Sobrien	vfs_hash_remove(vp);
28290075Sobrien
28390075Sobrien	/*
28490075Sobrien	 * Call nfscl_reclaimnode() to save attributes in the delegation,
28590075Sobrien	 * as required.
28690075Sobrien	 */
28790075Sobrien	if (vp->v_type == VREG)
28890075Sobrien		nfscl_reclaimnode(vp);
28990075Sobrien
29090075Sobrien	/*
29190075Sobrien	 * Free up any directory cookie structures and
29290075Sobrien	 * large file handle structures that might be associated with
29390075Sobrien	 * this nfs node.
29490075Sobrien	 */
29590075Sobrien	if (vp->v_type == VDIR) {
29690075Sobrien		dp = LIST_FIRST(&np->n_cookies);
29790075Sobrien		while (dp) {
29890075Sobrien			dp2 = dp;
29990075Sobrien			dp = LIST_NEXT(dp, ndm_list);
300132718Skan			FREE((caddr_t)dp2, M_NFSDIROFF);
301132718Skan		}
302117395Skan	}
303169689Skan	FREE((caddr_t)np->n_fhp, M_NFSFH);
304117395Skan	if (np->n_v4 != NULL)
305169689Skan		FREE((caddr_t)np->n_v4, M_NFSV4NODE);
306117395Skan	mtx_destroy(&np->n_mtx);
307169689Skan	uma_zfree(newnfsnode_zone, vp->v_data);
30890075Sobrien	vp->v_data = NULL;
30990075Sobrien	return (0);
31090075Sobrien}
31190075Sobrien
31290075Sobrien/*
31390075Sobrien * Invalidate both the access and attribute caches for this vnode.
31490075Sobrien */
31590075Sobrienvoid
31690075Sobrienncl_invalcaches(struct vnode *vp)
317117395Skan{
31890075Sobrien	struct nfsnode *np = VTONFS(vp);
31990075Sobrien	int i;
32090075Sobrien
321132718Skan	mtx_lock(&np->n_mtx);
322132718Skan	for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
32390075Sobrien		np->n_accesscache[i].stamp = 0;
324132718Skan	KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp);
32590075Sobrien	np->n_attrstamp = 0;
32690075Sobrien	KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
327169689Skan	mtx_unlock(&np->n_mtx);
328169689Skan}
329169689Skan
330169689Skan