1 /* $OpenBSD: nfs_node.c,v 1.6 1996/04/21 22:30:19 deraadt 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 40 */ 41 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/mount.h> 47 #include <sys/namei.h> 48 #include <sys/vnode.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 52 #include <nfs/rpcv2.h> 53 #include <nfs/nfsproto.h> 54 #include <nfs/nfs.h> 55 #include <nfs/nfsnode.h> 56 #include <nfs/nfsmount.h> 57 #include <nfs/nqnfs.h> 58 #include <nfs/nfs_var.h> 59 60 LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; 61 u_long nfsnodehash; 62 63 #define TRUE 1 64 #define FALSE 0 65 66 /* 67 * Initialize hash links for nfsnodes 68 * and build nfsnode free list. 69 */ 70 void 71 nfs_nhinit() 72 { 73 74 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash); 75 } 76 77 /* 78 * Compute an entry in the NFS hash table structure 79 */ 80 u_long 81 nfs_hash(fhp, fhsize) 82 register nfsfh_t *fhp; 83 int fhsize; 84 { 85 register u_char *fhpp; 86 register u_long fhsum; 87 register int i; 88 89 fhpp = &fhp->fh_bytes[0]; 90 fhsum = 0; 91 for (i = 0; i < fhsize; i++) 92 fhsum += *fhpp++; 93 return (fhsum); 94 } 95 96 /* 97 * Look up a vnode/nfsnode by file handle. 98 * Callers must check for mount points!! 99 * In all cases, a pointer to a 100 * nfsnode structure is returned. 101 */ 102 int 103 nfs_nget(mntp, fhp, fhsize, npp) 104 struct mount *mntp; 105 register nfsfh_t *fhp; 106 int fhsize; 107 struct nfsnode **npp; 108 { 109 #ifdef Lite2_integrated 110 struct proc *p = curproc; /* XXX */ 111 #endif 112 register struct nfsnode *np; 113 struct nfsnodehashhead *nhpp; 114 register struct vnode *vp; 115 extern int (**nfsv2_vnodeop_p)__P((void *)); 116 struct vnode *nvp; 117 int error; 118 119 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize)); 120 loop: 121 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { 122 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || 123 bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) 124 continue; 125 vp = NFSTOV(np); 126 #ifdef Lite2_integrated 127 if (vget(vp, LK_EXCLUSIVE, p)) 128 #else 129 if (vget(vp, 1)) 130 #endif 131 goto loop; 132 *npp = np; 133 return(0); 134 } 135 error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); 136 if (error) { 137 *npp = 0; 138 return (error); 139 } 140 vp = nvp; 141 MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); 142 bzero((caddr_t)np, sizeof *np); 143 vp->v_data = np; 144 np->n_vnode = vp; 145 /* 146 * Insert the nfsnode in the hash queue for its new file handle 147 */ 148 LIST_INSERT_HEAD(nhpp, np, n_hash); 149 if (fhsize > NFS_SMALLFH) { 150 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK); 151 } else 152 np->n_fhp = &np->n_fh; 153 bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); 154 np->n_fhsize = fhsize; 155 *npp = np; 156 return (0); 157 } 158 159 int 160 nfs_inactive(v) 161 void *v; 162 { 163 struct vop_inactive_args /* { 164 struct vnode *a_vp; 165 #ifdef Lite2_integrated 166 struct proc *a_p; 167 #endif 168 } */ *ap = v; 169 register struct nfsnode *np; 170 register struct sillyrename *sp; 171 struct proc *p = curproc; /* XXX */ 172 extern int prtactive; 173 174 np = VTONFS(ap->a_vp); 175 if (prtactive && ap->a_vp->v_usecount != 0) 176 vprint("nfs_inactive: pushing active", ap->a_vp); 177 if (ap->a_vp->v_type != VDIR) 178 sp = np->n_sillyrename; 179 else 180 sp = (struct sillyrename *)0; 181 np->n_sillyrename = (struct sillyrename *)0; 182 if (sp) { 183 /* 184 * Remove the silly file that was rename'd earlier 185 */ 186 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1); 187 nfs_removeit(sp); 188 crfree(sp->s_cred); 189 vrele(sp->s_dvp); 190 FREE((caddr_t)sp, M_NFSREQ); 191 } 192 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | 193 NQNFSNONCACHE | NQNFSWRITE); 194 #ifdef Lite2_integrated 195 VOP_UNLOCK(ap->a_vp, 0, ap->a_p); 196 #endif 197 return (0); 198 } 199 200 /* 201 * Reclaim an nfsnode so that it can be used for other purposes. 202 */ 203 int 204 nfs_reclaim(v) 205 void *v; 206 { 207 struct vop_reclaim_args /* { 208 struct vnode *a_vp; 209 } */ *ap = v; 210 register struct vnode *vp = ap->a_vp; 211 register struct nfsnode *np = VTONFS(vp); 212 register struct nfsmount *nmp = VFSTONFS(vp->v_mount); 213 register struct nfsdmap *dp, *dp2; 214 extern int prtactive; 215 216 if (prtactive && vp->v_usecount != 0) 217 vprint("nfs_reclaim: pushing active", vp); 218 219 LIST_REMOVE(np, n_hash); 220 221 /* 222 * For nqnfs, take it off the timer queue as required. 223 */ 224 if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0) { 225 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); 226 } 227 228 /* 229 * Free up any directory cookie structures and 230 * large file handle structures that might be associated with 231 * this nfs node. 232 */ 233 if (vp->v_type == VDIR) { 234 dp = np->n_cookies.lh_first; 235 while (dp) { 236 dp2 = dp; 237 dp = dp->ndm_list.le_next; 238 FREE((caddr_t)dp2, M_NFSDIROFF); 239 } 240 } 241 if (np->n_fhsize > NFS_SMALLFH) { 242 FREE((caddr_t)np->n_fhp, M_NFSBIGFH); 243 } 244 245 cache_purge(vp); 246 FREE(vp->v_data, M_NFSNODE); 247 vp->v_data = (void *)0; 248 return (0); 249 } 250 251 #ifndef Lite2_integrated 252 /* 253 * Lock an nfsnode 254 */ 255 int 256 nfs_lock(v) 257 void *v; 258 { 259 struct vop_lock_args /* { 260 struct vnode *a_vp; 261 } */ *ap = v; 262 register struct vnode *vp = ap->a_vp; 263 264 /* 265 * Ugh, another place where interruptible mounts will get hung. 266 * If you make this sleep interruptible, then you have to fix all 267 * the VOP_LOCK() calls to expect interruptibility. 268 */ 269 while (vp->v_flag & VXLOCK) { 270 vp->v_flag |= VXWANT; 271 (void) tsleep((caddr_t)vp, PINOD, "nfslck", 0); 272 } 273 if (vp->v_tag == VT_NON) 274 return (ENOENT); 275 return (0); 276 } 277 278 /* 279 * Unlock an nfsnode 280 */ 281 int 282 nfs_unlock(v) 283 void *v; 284 { 285 #if 0 286 struct vop_unlock_args /* { 287 struct vnode *a_vp; 288 } */ *ap = v; 289 #endif 290 return (0); 291 } 292 293 /* 294 * Check for a locked nfsnode 295 */ 296 int 297 nfs_islocked(v) 298 void *v; 299 { 300 #if 0 301 struct vop_islocked_args /* { 302 struct vnode *a_vp; 303 } */ *ap = v; 304 #endif 305 return (0); 306 } 307 #endif /* Lite2_integrated */ 308 309 /* 310 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 311 * done. Currently nothing to do. 312 */ 313 /* ARGSUSED */ 314 int 315 nfs_abortop(v) 316 void *v; 317 { 318 struct vop_abortop_args /* { 319 struct vnode *a_dvp; 320 struct componentname *a_cnp; 321 } */ *ap = v; 322 323 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 324 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 325 return (0); 326 } 327