1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)nfs_node.c 7.34 (Berkeley) 5/15/91 37 * $Id: nfs_node.c,v 1.2 1993/05/20 03:18:42 cgd Exp $ 38 */ 39 40 #include "param.h" 41 #include "systm.h" 42 #include "proc.h" 43 #include "mount.h" 44 #include "namei.h" 45 #include "vnode.h" 46 #include "kernel.h" 47 #include "malloc.h" 48 49 #include "nfsv2.h" 50 #include "nfs.h" 51 #include "nfsnode.h" 52 #include "nfsmount.h" 53 54 /* The request list head */ 55 extern struct nfsreq nfsreqh; 56 57 #define NFSNOHSZ 512 58 #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 59 #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 60 #else 61 #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 62 #endif 63 64 union nhead { 65 union nhead *nh_head[2]; 66 struct nfsnode *nh_chain[2]; 67 } nhead[NFSNOHSZ]; 68 69 #define TRUE 1 70 #define FALSE 0 71 72 /* 73 * Initialize hash links for nfsnodes 74 * and build nfsnode free list. 75 */ 76 nfs_nhinit() 77 { 78 register int i; 79 register union nhead *nh = nhead; 80 81 #ifndef lint 82 if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 83 panic("nfs_nhinit: too small"); 84 #endif /* not lint */ 85 for (i = NFSNOHSZ; --i >= 0; nh++) { 86 nh->nh_head[0] = nh; 87 nh->nh_head[1] = nh; 88 } 89 } 90 91 /* 92 * Compute an entry in the NFS hash table structure 93 */ 94 union nhead * 95 nfs_hash(fhp) 96 register nfsv2fh_t *fhp; 97 { 98 register u_char *fhpp; 99 register u_long fhsum; 100 int i; 101 102 fhpp = &fhp->fh_bytes[0]; 103 fhsum = 0; 104 for (i = 0; i < NFSX_FH; i++) 105 fhsum += *fhpp++; 106 return (&nhead[NFSNOHASH(fhsum)]); 107 } 108 109 /* 110 * Look up a vnode/nfsnode by file handle. 111 * Callers must check for mount points!! 112 * In all cases, a pointer to a 113 * nfsnode structure is returned. 114 */ 115 nfs_nget(mntp, fhp, npp) 116 struct mount *mntp; 117 register nfsv2fh_t *fhp; 118 struct nfsnode **npp; 119 { 120 register struct nfsnode *np; 121 register struct vnode *vp; 122 extern struct vnodeops nfsv2_vnodeops; 123 struct vnode *nvp; 124 union nhead *nh; 125 int error; 126 127 nh = nfs_hash(fhp); 128 loop: 129 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 130 if (mntp != NFSTOV(np)->v_mount || 131 bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 132 continue; 133 if ((np->n_flag & NLOCKED) != 0) { 134 np->n_flag |= NWANT; 135 (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0); 136 goto loop; 137 } 138 vp = NFSTOV(np); 139 if (vget(vp)) 140 goto loop; 141 *npp = np; 142 return(0); 143 } 144 if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 145 *npp = 0; 146 return (error); 147 } 148 vp = nvp; 149 np = VTONFS(vp); 150 np->n_vnode = vp; 151 /* 152 * Insert the nfsnode in the hash queue for its new file handle 153 */ 154 np->n_flag = 0; 155 insque(np, nh); 156 nfs_lock(vp); 157 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 158 np->n_attrstamp = 0; 159 np->n_direofoffset = 0; 160 np->n_sillyrename = (struct sillyrename *)0; 161 np->n_size = 0; 162 np->n_mtime = 0; 163 *npp = np; 164 return (0); 165 } 166 167 nfs_inactive(vp, p) 168 struct vnode *vp; 169 struct proc *p; 170 { 171 register struct nfsnode *np; 172 register struct sillyrename *sp; 173 struct nfsnode *dnp; 174 extern int prtactive; 175 176 np = VTONFS(vp); 177 if (prtactive && vp->v_usecount != 0) 178 vprint("nfs_inactive: pushing active", vp); 179 nfs_lock(vp); 180 sp = np->n_sillyrename; 181 np->n_sillyrename = (struct sillyrename *)0; 182 if (sp) { 183 /* 184 * Remove the silly file that was rename'd earlier 185 */ 186 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 187 sp->s_dvp = NFSTOV(dnp); 188 nfs_removeit(sp, p); 189 nfs_nput(sp->s_dvp); 190 } 191 crfree(sp->s_cred); 192 vrele(sp->s_dvp); 193 free((caddr_t)sp, M_NFSREQ); 194 } 195 nfs_unlock(vp); 196 np->n_flag &= NMODIFIED; 197 #ifdef notdef 198 /* 199 * Scan the request list for any requests left hanging about 200 */ 201 s = splnet(); 202 rep = nfsreqh.r_next; 203 while (rep && rep != &nfsreqh) { 204 if (rep->r_vp == vp) { 205 rep->r_prev->r_next = rep2 = rep->r_next; 206 rep->r_next->r_prev = rep->r_prev; 207 m_freem(rep->r_mreq); 208 if (rep->r_mrep != NULL) 209 m_freem(rep->r_mrep); 210 free((caddr_t)rep, M_NFSREQ); 211 rep = rep2; 212 } else 213 rep = rep->r_next; 214 } 215 splx(s); 216 #endif 217 return (0); 218 } 219 220 /* 221 * Reclaim an nfsnode so that it can be used for other purposes. 222 */ 223 nfs_reclaim(vp) 224 register struct vnode *vp; 225 { 226 register struct nfsnode *np = VTONFS(vp); 227 extern int prtactive; 228 229 if (prtactive && vp->v_usecount != 0) 230 vprint("nfs_reclaim: pushing active", vp); 231 /* 232 * Remove the nfsnode from its hash chain. 233 */ 234 remque(np); 235 np->n_forw = np; 236 np->n_back = np; 237 cache_purge(vp); 238 np->n_flag = 0; 239 np->n_direofoffset = 0; 240 return (0); 241 } 242 243 /* 244 * In theory, NFS does not need locking, but we make provision 245 * for doing it just in case it is needed. 246 */ 247 int donfslocking = 0; 248 /* 249 * Lock an nfsnode 250 */ 251 252 nfs_lock(vp) 253 struct vnode *vp; 254 { 255 register struct nfsnode *np = VTONFS(vp); 256 257 if (!donfslocking) 258 return; 259 while (np->n_flag & NLOCKED) { 260 np->n_flag |= NWANT; 261 if (np->n_lockholder == curproc->p_pid) 262 panic("locking against myself"); 263 np->n_lockwaiter = curproc->p_pid; 264 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 265 } 266 np->n_lockwaiter = 0; 267 np->n_lockholder = curproc->p_pid; 268 np->n_flag |= NLOCKED; 269 } 270 271 /* 272 * Unlock an nfsnode 273 */ 274 nfs_unlock(vp) 275 struct vnode *vp; 276 { 277 register struct nfsnode *np = VTONFS(vp); 278 279 np->n_lockholder = 0; 280 np->n_flag &= ~NLOCKED; 281 if (np->n_flag & NWANT) { 282 np->n_flag &= ~NWANT; 283 wakeup((caddr_t)np); 284 } 285 } 286 287 /* 288 * Check for a locked nfsnode 289 */ 290 nfs_islocked(vp) 291 struct vnode *vp; 292 { 293 294 if (VTONFS(vp)->n_flag & NLOCKED) 295 return (1); 296 return (0); 297 } 298 299 /* 300 * Unlock and vrele() 301 * since I can't decide if dirs. should be locked, I will check for 302 * the lock and be flexible 303 */ 304 nfs_nput(vp) 305 struct vnode *vp; 306 { 307 register struct nfsnode *np = VTONFS(vp); 308 309 if (np->n_flag & NLOCKED) 310 nfs_unlock(vp); 311 vrele(vp); 312 } 313 314 /* 315 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 316 * done. Currently nothing to do. 317 */ 318 /* ARGSUSED */ 319 nfs_abortop(ndp) 320 struct nameidata *ndp; 321 { 322 323 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 324 FREE(ndp->ni_pnbuf, M_NAMEI); 325 return (0); 326 } 327