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.3 1993/07/28 02:22:25 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 np->n_lockf = 0; 164 *npp = np; 165 return (0); 166 } 167 168 nfs_inactive(vp, p) 169 struct vnode *vp; 170 struct proc *p; 171 { 172 register struct nfsnode *np; 173 register struct sillyrename *sp; 174 struct nfsnode *dnp; 175 extern int prtactive; 176 177 np = VTONFS(vp); 178 if (prtactive && vp->v_usecount != 0) 179 vprint("nfs_inactive: pushing active", vp); 180 nfs_lock(vp); 181 sp = np->n_sillyrename; 182 np->n_sillyrename = (struct sillyrename *)0; 183 if (sp) { 184 /* 185 * Remove the silly file that was rename'd earlier 186 */ 187 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 188 sp->s_dvp = NFSTOV(dnp); 189 nfs_removeit(sp, p); 190 nfs_nput(sp->s_dvp); 191 } 192 crfree(sp->s_cred); 193 vrele(sp->s_dvp); 194 free((caddr_t)sp, M_NFSREQ); 195 } 196 nfs_unlock(vp); 197 np->n_flag &= NMODIFIED; 198 #ifdef notdef 199 /* 200 * Scan the request list for any requests left hanging about 201 */ 202 s = splnet(); 203 rep = nfsreqh.r_next; 204 while (rep && rep != &nfsreqh) { 205 if (rep->r_vp == vp) { 206 rep->r_prev->r_next = rep2 = rep->r_next; 207 rep->r_next->r_prev = rep->r_prev; 208 m_freem(rep->r_mreq); 209 if (rep->r_mrep != NULL) 210 m_freem(rep->r_mrep); 211 free((caddr_t)rep, M_NFSREQ); 212 rep = rep2; 213 } else 214 rep = rep->r_next; 215 } 216 splx(s); 217 #endif 218 return (0); 219 } 220 221 /* 222 * Reclaim an nfsnode so that it can be used for other purposes. 223 */ 224 nfs_reclaim(vp) 225 register struct vnode *vp; 226 { 227 register struct nfsnode *np = VTONFS(vp); 228 extern int prtactive; 229 230 if (prtactive && vp->v_usecount != 0) 231 vprint("nfs_reclaim: pushing active", vp); 232 /* 233 * Remove the nfsnode from its hash chain. 234 */ 235 remque(np); 236 np->n_forw = np; 237 np->n_back = np; 238 cache_purge(vp); 239 np->n_flag = 0; 240 np->n_direofoffset = 0; 241 return (0); 242 } 243 244 /* 245 * In theory, NFS does not need locking, but we make provision 246 * for doing it just in case it is needed. 247 */ 248 int donfslocking = 0; 249 /* 250 * Lock an nfsnode 251 */ 252 253 nfs_lock(vp) 254 struct vnode *vp; 255 { 256 register struct nfsnode *np = VTONFS(vp); 257 258 if (!donfslocking) 259 return; 260 while (np->n_flag & NLOCKED) { 261 np->n_flag |= NWANT; 262 if (np->n_lockholder == curproc->p_pid) 263 panic("locking against myself"); 264 np->n_lockwaiter = curproc->p_pid; 265 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 266 } 267 np->n_lockwaiter = 0; 268 np->n_lockholder = curproc->p_pid; 269 np->n_flag |= NLOCKED; 270 } 271 272 /* 273 * Unlock an nfsnode 274 */ 275 nfs_unlock(vp) 276 struct vnode *vp; 277 { 278 register struct nfsnode *np = VTONFS(vp); 279 280 np->n_lockholder = 0; 281 np->n_flag &= ~NLOCKED; 282 if (np->n_flag & NWANT) { 283 np->n_flag &= ~NWANT; 284 wakeup((caddr_t)np); 285 } 286 } 287 288 /* 289 * Check for a locked nfsnode 290 */ 291 nfs_islocked(vp) 292 struct vnode *vp; 293 { 294 295 if (VTONFS(vp)->n_flag & NLOCKED) 296 return (1); 297 return (0); 298 } 299 300 /* 301 * Unlock and vrele() 302 * since I can't decide if dirs. should be locked, I will check for 303 * the lock and be flexible 304 */ 305 nfs_nput(vp) 306 struct vnode *vp; 307 { 308 register struct nfsnode *np = VTONFS(vp); 309 310 if (np->n_flag & NLOCKED) 311 nfs_unlock(vp); 312 vrele(vp); 313 } 314 315 /* 316 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 317 * done. Currently nothing to do. 318 */ 319 /* ARGSUSED */ 320 nfs_abortop(ndp) 321 struct nameidata *ndp; 322 { 323 324 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 325 FREE(ndp->ni_pnbuf, M_NAMEI); 326 return (0); 327 } 328