19ec7b004SRick Macklem /*- 29ec7b004SRick Macklem * Copyright (c) 1989, 1993 39ec7b004SRick Macklem * The Regents of the University of California. All rights reserved. 49ec7b004SRick Macklem * 59ec7b004SRick Macklem * This code is derived from software contributed to Berkeley by 69ec7b004SRick Macklem * Rick Macklem at The University of Guelph. 79ec7b004SRick Macklem * 89ec7b004SRick Macklem * Redistribution and use in source and binary forms, with or without 99ec7b004SRick Macklem * modification, are permitted provided that the following conditions 109ec7b004SRick Macklem * are met: 119ec7b004SRick Macklem * 1. Redistributions of source code must retain the above copyright 129ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer. 139ec7b004SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 149ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer in the 159ec7b004SRick Macklem * documentation and/or other materials provided with the distribution. 169ec7b004SRick Macklem * 4. Neither the name of the University nor the names of its contributors 179ec7b004SRick Macklem * may be used to endorse or promote products derived from this software 189ec7b004SRick Macklem * without specific prior written permission. 199ec7b004SRick Macklem * 209ec7b004SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 219ec7b004SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 229ec7b004SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239ec7b004SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 249ec7b004SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 259ec7b004SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 269ec7b004SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 279ec7b004SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289ec7b004SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 299ec7b004SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 309ec7b004SRick Macklem * SUCH DAMAGE. 319ec7b004SRick Macklem * 329ec7b004SRick Macklem * from nfs_node.c 8.6 (Berkeley) 5/22/95 339ec7b004SRick Macklem */ 349ec7b004SRick Macklem 359ec7b004SRick Macklem #include <sys/cdefs.h> 369ec7b004SRick Macklem __FBSDID("$FreeBSD$"); 379ec7b004SRick Macklem 389ec7b004SRick Macklem #include <sys/param.h> 399ec7b004SRick Macklem #include <sys/systm.h> 40*ca27c028SRick Macklem #include <sys/fcntl.h> 419ec7b004SRick Macklem #include <sys/lock.h> 429ec7b004SRick Macklem #include <sys/malloc.h> 439ec7b004SRick Macklem #include <sys/mount.h> 449ec7b004SRick Macklem #include <sys/namei.h> 459ec7b004SRick Macklem #include <sys/proc.h> 469ec7b004SRick Macklem #include <sys/socket.h> 479ec7b004SRick Macklem #include <sys/sysctl.h> 489ec7b004SRick Macklem #include <sys/vnode.h> 499ec7b004SRick Macklem 509ec7b004SRick Macklem #include <vm/uma.h> 519ec7b004SRick Macklem 529ec7b004SRick Macklem #include <fs/nfs/nfsport.h> 539ec7b004SRick Macklem #include <fs/nfsclient/nfsnode.h> 549ec7b004SRick Macklem #include <fs/nfsclient/nfsmount.h> 559ec7b004SRick Macklem #include <fs/nfsclient/nfs.h> 569ec7b004SRick Macklem 57*ca27c028SRick Macklem #include <nfs/nfs_lock.h> 58*ca27c028SRick Macklem 599ec7b004SRick Macklem extern struct vop_vector newnfs_vnodeops; 609ec7b004SRick Macklem extern struct buf_ops buf_ops_newnfs; 619ec7b004SRick Macklem MALLOC_DECLARE(M_NEWNFSREQ); 629ec7b004SRick Macklem 639ec7b004SRick Macklem uma_zone_t newnfsnode_zone; 649ec7b004SRick Macklem 659ec7b004SRick Macklem void 669ec7b004SRick Macklem ncl_nhinit(void) 679ec7b004SRick Macklem { 689ec7b004SRick Macklem 699ec7b004SRick Macklem newnfsnode_zone = uma_zcreate("NCLNODE", sizeof(struct nfsnode), NULL, 709ec7b004SRick Macklem NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 719ec7b004SRick Macklem } 729ec7b004SRick Macklem 739ec7b004SRick Macklem void 749ec7b004SRick Macklem ncl_nhuninit(void) 759ec7b004SRick Macklem { 769ec7b004SRick Macklem uma_zdestroy(newnfsnode_zone); 779ec7b004SRick Macklem } 789ec7b004SRick Macklem 799ec7b004SRick Macklem /* 809ec7b004SRick Macklem * ONLY USED FOR THE ROOT DIRECTORY. nfscl_nget() does the rest. If this 819ec7b004SRick Macklem * function is going to be used to get Regular Files, code must be added 829ec7b004SRick Macklem * to fill in the "struct nfsv4node". 839ec7b004SRick Macklem * Look up a vnode/nfsnode by file handle. 849ec7b004SRick Macklem * Callers must check for mount points!! 859ec7b004SRick Macklem * In all cases, a pointer to a 869ec7b004SRick Macklem * nfsnode structure is returned. 879ec7b004SRick Macklem */ 889ec7b004SRick Macklem int 899ec7b004SRick Macklem ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp) 909ec7b004SRick Macklem { 919ec7b004SRick Macklem struct thread *td = curthread; /* XXX */ 929ec7b004SRick Macklem struct nfsnode *np; 939ec7b004SRick Macklem struct vnode *vp; 949ec7b004SRick Macklem struct vnode *nvp; 959ec7b004SRick Macklem int error; 969ec7b004SRick Macklem u_int hash; 979ec7b004SRick Macklem struct nfsmount *nmp; 989ec7b004SRick Macklem struct nfsfh *nfhp; 999ec7b004SRick Macklem 1009ec7b004SRick Macklem nmp = VFSTONFS(mntp); 1019ec7b004SRick Macklem *npp = NULL; 1029ec7b004SRick Macklem 1039ec7b004SRick Macklem hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT); 1049ec7b004SRick Macklem 1059ec7b004SRick Macklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize, 1069ec7b004SRick Macklem M_NFSFH, M_WAITOK); 1079ec7b004SRick Macklem bcopy(fhp, &nfhp->nfh_fh[0], fhsize); 1089ec7b004SRick Macklem nfhp->nfh_len = fhsize; 1099ec7b004SRick Macklem error = vfs_hash_get(mntp, hash, LK_EXCLUSIVE, 1109ec7b004SRick Macklem td, &nvp, newnfs_vncmpf, nfhp); 1119ec7b004SRick Macklem FREE(nfhp, M_NFSFH); 1129ec7b004SRick Macklem if (error) 1139ec7b004SRick Macklem return (error); 1149ec7b004SRick Macklem if (nvp != NULL) { 1159ec7b004SRick Macklem *npp = VTONFS(nvp); 1169ec7b004SRick Macklem return (0); 1179ec7b004SRick Macklem } 1189ec7b004SRick Macklem 1199ec7b004SRick Macklem /* 1209ec7b004SRick Macklem * Allocate before getnewvnode since doing so afterward 1219ec7b004SRick Macklem * might cause a bogus v_data pointer to get dereferenced 1229ec7b004SRick Macklem * elsewhere if zalloc should block. 1239ec7b004SRick Macklem */ 1249ec7b004SRick Macklem np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO); 1259ec7b004SRick Macklem 1269ec7b004SRick Macklem error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp); 1279ec7b004SRick Macklem if (error) { 1289ec7b004SRick Macklem uma_zfree(newnfsnode_zone, np); 1299ec7b004SRick Macklem return (error); 1309ec7b004SRick Macklem } 1319ec7b004SRick Macklem vp = nvp; 1329ec7b004SRick Macklem vp->v_bufobj.bo_ops = &buf_ops_newnfs; 1339ec7b004SRick Macklem vp->v_data = np; 1349ec7b004SRick Macklem np->n_vnode = vp; 1359ec7b004SRick Macklem /* 1369ec7b004SRick Macklem * Initialize the mutex even if the vnode is going to be a loser. 1379ec7b004SRick Macklem * This simplifies the logic in reclaim, which can then unconditionally 1389ec7b004SRick Macklem * destroy the mutex (in the case of the loser, or if hash_insert 1399ec7b004SRick Macklem * happened to return an error no special casing is needed). 1409ec7b004SRick Macklem */ 1419ec7b004SRick Macklem mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK); 1429ec7b004SRick Macklem /* 1439ec7b004SRick Macklem * NFS supports recursive and shared locking. 1449ec7b004SRick Macklem */ 1453634d5b2SJohn Baldwin lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); 1469ec7b004SRick Macklem VN_LOCK_AREC(vp); 1479ec7b004SRick Macklem VN_LOCK_ASHARE(vp); 1489ec7b004SRick Macklem /* 1499ec7b004SRick Macklem * Are we getting the root? If so, make sure the vnode flags 1509ec7b004SRick Macklem * are correct 1519ec7b004SRick Macklem */ 1529ec7b004SRick Macklem if ((fhsize == nmp->nm_fhsize) && 1539ec7b004SRick Macklem !bcmp(fhp, nmp->nm_fh, fhsize)) { 1549ec7b004SRick Macklem if (vp->v_type == VNON) 1559ec7b004SRick Macklem vp->v_type = VDIR; 1569ec7b004SRick Macklem vp->v_vflag |= VV_ROOT; 1579ec7b004SRick Macklem } 1589ec7b004SRick Macklem 1599ec7b004SRick Macklem MALLOC(np->n_fhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize, 1609ec7b004SRick Macklem M_NFSFH, M_WAITOK); 1619ec7b004SRick Macklem bcopy(fhp, np->n_fhp->nfh_fh, fhsize); 1629ec7b004SRick Macklem np->n_fhp->nfh_len = fhsize; 1639ec7b004SRick Macklem error = insmntque(vp, mntp); 1649ec7b004SRick Macklem if (error != 0) { 1659ec7b004SRick Macklem *npp = NULL; 1669ec7b004SRick Macklem FREE((caddr_t)np->n_fhp, M_NFSFH); 1679ec7b004SRick Macklem mtx_destroy(&np->n_mtx); 1689ec7b004SRick Macklem uma_zfree(newnfsnode_zone, np); 1699ec7b004SRick Macklem return (error); 1709ec7b004SRick Macklem } 1719ec7b004SRick Macklem error = vfs_hash_insert(vp, hash, LK_EXCLUSIVE, 1729ec7b004SRick Macklem td, &nvp, newnfs_vncmpf, np->n_fhp); 1739ec7b004SRick Macklem if (error) 1749ec7b004SRick Macklem return (error); 1759ec7b004SRick Macklem if (nvp != NULL) { 1769ec7b004SRick Macklem *npp = VTONFS(nvp); 1779ec7b004SRick Macklem /* vfs_hash_insert() vput()'s the losing vnode */ 1789ec7b004SRick Macklem return (0); 1799ec7b004SRick Macklem } 1809ec7b004SRick Macklem *npp = np; 1819ec7b004SRick Macklem 1829ec7b004SRick Macklem return (0); 1839ec7b004SRick Macklem } 1849ec7b004SRick Macklem 1859ec7b004SRick Macklem int 1869ec7b004SRick Macklem ncl_inactive(struct vop_inactive_args *ap) 1879ec7b004SRick Macklem { 1889ec7b004SRick Macklem struct nfsnode *np; 1899ec7b004SRick Macklem struct sillyrename *sp; 190d00a615aSRick Macklem struct vnode *vp = ap->a_vp; 1919ec7b004SRick Macklem 192d00a615aSRick Macklem np = VTONFS(vp); 193d00a615aSRick Macklem if (prtactive && vrefcnt(vp) != 0) 194d00a615aSRick Macklem vprint("ncl_inactive: pushing active", vp); 19547a59856SRick Macklem 196d00a615aSRick Macklem if (NFS_ISV4(vp) && vp->v_type == VREG) { 19747a59856SRick Macklem /* 198fdd88deeSRick Macklem * Since mmap()'d files do I/O after VOP_CLOSE(), the NFSv4 199fdd88deeSRick Macklem * Close operations are delayed until now. Any dirty buffers 200fdd88deeSRick Macklem * must be flushed before the close, so that the stateid is 201fdd88deeSRick Macklem * available for the writes. 20247a59856SRick Macklem */ 20367c5c2d2SRick Macklem (void) ncl_flush(vp, MNT_WAIT, NULL, ap->a_td, 1, 0); 204d00a615aSRick Macklem (void) nfsrpc_close(vp, 1, ap->a_td); 205fdd88deeSRick Macklem } 20647a59856SRick Macklem 207d00a615aSRick Macklem if (vp->v_type != VDIR) { 2089ec7b004SRick Macklem sp = np->n_sillyrename; 2099ec7b004SRick Macklem np->n_sillyrename = NULL; 2109ec7b004SRick Macklem } else 2119ec7b004SRick Macklem sp = NULL; 2129ec7b004SRick Macklem if (sp) { 213d00a615aSRick Macklem (void) ncl_vinvalbuf(vp, 0, ap->a_td, 1); 2149ec7b004SRick Macklem /* 2159ec7b004SRick Macklem * Remove the silly file that was rename'd earlier 2169ec7b004SRick Macklem */ 217d00a615aSRick Macklem ncl_removeit(sp, vp); 2189ec7b004SRick Macklem crfree(sp->s_cred); 2199ec7b004SRick Macklem vrele(sp->s_dvp); 2209ec7b004SRick Macklem FREE((caddr_t)sp, M_NEWNFSREQ); 2219ec7b004SRick Macklem } 2229ec7b004SRick Macklem np->n_flag &= NMODIFIED; 2239ec7b004SRick Macklem return (0); 2249ec7b004SRick Macklem } 2259ec7b004SRick Macklem 2269ec7b004SRick Macklem /* 2279ec7b004SRick Macklem * Reclaim an nfsnode so that it can be used for other purposes. 2289ec7b004SRick Macklem */ 2299ec7b004SRick Macklem int 2309ec7b004SRick Macklem ncl_reclaim(struct vop_reclaim_args *ap) 2319ec7b004SRick Macklem { 2329ec7b004SRick Macklem struct vnode *vp = ap->a_vp; 2339ec7b004SRick Macklem struct nfsnode *np = VTONFS(vp); 2349ec7b004SRick Macklem struct nfsdmap *dp, *dp2; 2359ec7b004SRick Macklem 2369ec7b004SRick Macklem if (prtactive && vrefcnt(vp) != 0) 2379ec7b004SRick Macklem vprint("ncl_reclaim: pushing active", vp); 2389ec7b004SRick Macklem 2399ec7b004SRick Macklem /* 2409ec7b004SRick Macklem * If the NLM is running, give it a chance to abort pending 2419ec7b004SRick Macklem * locks. 2429ec7b004SRick Macklem */ 243*ca27c028SRick Macklem if (nfs_reclaim_p != NULL) 244*ca27c028SRick Macklem nfs_reclaim_p(ap); 2459ec7b004SRick Macklem 2469ec7b004SRick Macklem /* 2479ec7b004SRick Macklem * Destroy the vm object and flush associated pages. 2489ec7b004SRick Macklem */ 2499ec7b004SRick Macklem vnode_destroy_vobject(vp); 2509ec7b004SRick Macklem 2519ec7b004SRick Macklem vfs_hash_remove(vp); 2529ec7b004SRick Macklem 2539ec7b004SRick Macklem /* 2549ec7b004SRick Macklem * Call nfscl_reclaimnode() to save attributes in the delegation, 2559ec7b004SRick Macklem * as required. 2569ec7b004SRick Macklem */ 2579ec7b004SRick Macklem if (vp->v_type == VREG) 2589ec7b004SRick Macklem nfscl_reclaimnode(vp); 2599ec7b004SRick Macklem 2609ec7b004SRick Macklem /* 2619ec7b004SRick Macklem * Free up any directory cookie structures and 2629ec7b004SRick Macklem * large file handle structures that might be associated with 2639ec7b004SRick Macklem * this nfs node. 2649ec7b004SRick Macklem */ 2659ec7b004SRick Macklem if (vp->v_type == VDIR) { 2669ec7b004SRick Macklem dp = LIST_FIRST(&np->n_cookies); 2679ec7b004SRick Macklem while (dp) { 2689ec7b004SRick Macklem dp2 = dp; 2699ec7b004SRick Macklem dp = LIST_NEXT(dp, ndm_list); 2709ec7b004SRick Macklem FREE((caddr_t)dp2, M_NFSDIROFF); 2719ec7b004SRick Macklem } 2729ec7b004SRick Macklem } 2739ec7b004SRick Macklem FREE((caddr_t)np->n_fhp, M_NFSFH); 2749ec7b004SRick Macklem if (np->n_v4 != NULL) 2759ec7b004SRick Macklem FREE((caddr_t)np->n_v4, M_NFSV4NODE); 2769ec7b004SRick Macklem mtx_destroy(&np->n_mtx); 2779ec7b004SRick Macklem uma_zfree(newnfsnode_zone, vp->v_data); 2789ec7b004SRick Macklem vp->v_data = NULL; 2799ec7b004SRick Macklem return (0); 2809ec7b004SRick Macklem } 2819ec7b004SRick Macklem 2829ec7b004SRick Macklem /* 2839ec7b004SRick Macklem * Invalidate both the access and attribute caches for this vnode. 2849ec7b004SRick Macklem */ 2859ec7b004SRick Macklem void 2869ec7b004SRick Macklem ncl_invalcaches(struct vnode *vp) 2879ec7b004SRick Macklem { 2889ec7b004SRick Macklem struct nfsnode *np = VTONFS(vp); 2899ec7b004SRick Macklem int i; 2909ec7b004SRick Macklem 2919ec7b004SRick Macklem mtx_lock(&np->n_mtx); 2929ec7b004SRick Macklem for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 2939ec7b004SRick Macklem np->n_accesscache[i].stamp = 0; 2949ec7b004SRick Macklem np->n_attrstamp = 0; 2959ec7b004SRick Macklem mtx_unlock(&np->n_mtx); 2969ec7b004SRick Macklem } 2979ec7b004SRick Macklem 298