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