1 /* $OpenBSD: nfs_node.c,v 1.55 2010/12/21 20:14:43 thib Exp $ */ 2 /* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 36 */ 37 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/proc.h> 42 #include <sys/mount.h> 43 #include <sys/namei.h> 44 #include <sys/vnode.h> 45 #include <sys/kernel.h> 46 #include <sys/malloc.h> 47 #include <sys/pool.h> 48 #include <sys/rwlock.h> 49 #include <sys/queue.h> 50 51 #include <nfs/rpcv2.h> 52 #include <nfs/nfsproto.h> 53 #include <nfs/nfs.h> 54 #include <nfs/nfsnode.h> 55 #include <nfs/nfsmount.h> 56 #include <nfs/nfs_var.h> 57 58 struct pool nfs_node_pool; 59 extern int prtactive; 60 61 struct rwlock nfs_hashlock = RWLOCK_INITIALIZER("nfshshlk"); 62 63 /* XXX */ 64 extern struct vops nfs_vops; 65 66 /* filehandle to node lookup. */ 67 static __inline int 68 nfsnode_cmp(const struct nfsnode *a, const struct nfsnode *b) 69 { 70 if (a->n_fhsize != b->n_fhsize) 71 return (a->n_fhsize - b->n_fhsize); 72 return (memcmp(a->n_fhp, b->n_fhp, a->n_fhsize)); 73 } 74 75 RB_PROTOTYPE(nfs_nodetree, nfsnode, n_entry, nfsnode_cmp); 76 RB_GENERATE(nfs_nodetree, nfsnode, n_entry, nfsnode_cmp); 77 78 /* 79 * Look up a vnode/nfsnode by file handle. 80 * Callers must check for mount points!! 81 * In all cases, a pointer to a 82 * nfsnode structure is returned. 83 */ 84 int 85 nfs_nget(struct mount *mnt, nfsfh_t *fh, int fhsize, struct nfsnode **npp) 86 { 87 struct nfsmount *nmp; 88 struct nfsnode *np, find, *np2; 89 struct vnode *vp, *nvp; 90 struct proc *p = curproc; /* XXX */ 91 int error; 92 93 nmp = VFSTONFS(mnt); 94 95 loop: 96 rw_enter_write(&nfs_hashlock); 97 find.n_fhp = fh; 98 find.n_fhsize = fhsize; 99 np = RB_FIND(nfs_nodetree, &nmp->nm_ntree, &find); 100 if (np != NULL) { 101 rw_exit_write(&nfs_hashlock); 102 vp = NFSTOV(np); 103 error = vget(vp, LK_EXCLUSIVE, p); 104 if (error) 105 goto loop; 106 *npp = np; 107 return (0); 108 } 109 110 /* 111 * getnewvnode() could recycle a vnode, potentially formerly 112 * owned by NFS. This will cause a VOP_RECLAIM() to happen, 113 * which will cause recursive locking, so we unlock before 114 * calling getnewvnode() lock again afterwards, but must check 115 * to see if this nfsnode has been added while we did not hold 116 * the lock. 117 */ 118 rw_exit_write(&nfs_hashlock); 119 error = getnewvnode(VT_NFS, mnt, &nfs_vops, &nvp); 120 /* note that we don't have this vnode set up completely yet */ 121 rw_enter_write(&nfs_hashlock); 122 if (error) { 123 *npp = NULL; 124 rw_exit_write(&nfs_hashlock); 125 return (error); 126 } 127 nvp->v_flag |= VLARVAL; 128 np = RB_FIND(nfs_nodetree, &nmp->nm_ntree, &find); 129 if (np != NULL) { 130 vgone(nvp); 131 rw_exit_write(&nfs_hashlock); 132 goto loop; 133 } 134 135 vp = nvp; 136 np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO); 137 vp->v_data = np; 138 /* we now have an nfsnode on this vnode */ 139 vp->v_flag &= ~VLARVAL; 140 np->n_vnode = vp; 141 142 rw_init(&np->n_commitlock, "nfs_commitlk"); 143 144 /* 145 * Are we getting the root? If so, make sure the vnode flags 146 * are correct 147 */ 148 if ((fhsize == nmp->nm_fhsize) && !bcmp(fh, nmp->nm_fh, fhsize)) { 149 if (vp->v_type == VNON) 150 vp->v_type = VDIR; 151 vp->v_flag |= VROOT; 152 } 153 154 np->n_fhp = &np->n_fh; 155 bcopy(fh, np->n_fhp, fhsize); 156 np->n_fhsize = fhsize; 157 np2 = RB_INSERT(nfs_nodetree, &nmp->nm_ntree, np); 158 KASSERT(np2 == NULL); 159 np->n_accstamp = -1; 160 rw_exit(&nfs_hashlock); 161 *npp = np; 162 163 return (0); 164 } 165 166 int 167 nfs_inactive(void *v) 168 { 169 struct vop_inactive_args *ap = v; 170 struct nfsnode *np; 171 struct sillyrename *sp; 172 173 #ifdef DIAGNOSTIC 174 if (prtactive && ap->a_vp->v_usecount != 0) 175 vprint("nfs_inactive: pushing active", ap->a_vp); 176 #endif 177 if (ap->a_vp->v_flag & VLARVAL) 178 /* 179 * vnode was incompletely set up, just return 180 * as we are throwing it away. 181 */ 182 return(0); 183 #ifdef DIAGNOSTIC 184 if (ap->a_vp->v_data == NULL) 185 panic("NULL v_data (no nfsnode set up?) in vnode %p", 186 ap->a_vp); 187 #endif 188 np = VTONFS(ap->a_vp); 189 if (ap->a_vp->v_type != VDIR) { 190 sp = np->n_sillyrename; 191 np->n_sillyrename = NULL; 192 } else 193 sp = NULL; 194 if (sp) { 195 /* 196 * Remove the silly file that was rename'd earlier 197 */ 198 nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, curproc); 199 nfs_removeit(sp); 200 crfree(sp->s_cred); 201 vrele(sp->s_dvp); 202 free(sp, M_NFSREQ); 203 } 204 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT); 205 206 VOP_UNLOCK(ap->a_vp, 0, ap->a_p); 207 return (0); 208 } 209 210 /* 211 * Reclaim an nfsnode so that it can be used for other purposes. 212 */ 213 int 214 nfs_reclaim(void *v) 215 { 216 struct vop_reclaim_args *ap = v; 217 struct vnode *vp = ap->a_vp; 218 struct nfsmount *nmp; 219 struct nfsnode *np = VTONFS(vp); 220 221 #ifdef DIAGNOSTIC 222 if (prtactive && vp->v_usecount != 0) 223 vprint("nfs_reclaim: pushing active", vp); 224 #endif 225 if (ap->a_vp->v_flag & VLARVAL) 226 /* 227 * vnode was incompletely set up, just return 228 * as we are throwing it away. 229 */ 230 return(0); 231 #ifdef DIAGNOSTIC 232 if (ap->a_vp->v_data == NULL) 233 panic("NULL v_data (no nfsnode set up?) in vnode %p", 234 ap->a_vp); 235 #endif 236 nmp = VFSTONFS(vp->v_mount); 237 rw_enter_write(&nfs_hashlock); 238 RB_REMOVE(nfs_nodetree, &nmp->nm_ntree, np); 239 rw_exit_write(&nfs_hashlock); 240 241 if (np->n_rcred) 242 crfree(np->n_rcred); 243 if (np->n_wcred) 244 crfree(np->n_wcred); 245 246 cache_purge(vp); 247 pool_put(&nfs_node_pool, vp->v_data); 248 vp->v_data = NULL; 249 250 return (0); 251 } 252