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 are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)nfs_node.c 7.28 (Berkeley) 06/21/90 21 */ 22 23 #include "param.h" 24 #include "systm.h" 25 #include "user.h" 26 #include "proc.h" 27 #include "mount.h" 28 #include "vnode.h" 29 #include "errno.h" 30 #include "nfsv2.h" 31 #include "nfs.h" 32 #include "nfsnode.h" 33 #include "nfsmount.h" 34 #include "kernel.h" 35 #include "malloc.h" 36 37 /* The request list head */ 38 extern struct nfsreq nfsreqh; 39 40 #define NFSNOHSZ 512 41 #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 42 #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 43 #else 44 #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 45 #endif 46 47 union nhead { 48 union nhead *nh_head[2]; 49 struct nfsnode *nh_chain[2]; 50 } nhead[NFSNOHSZ]; 51 52 #define TRUE 1 53 #define FALSE 0 54 55 /* 56 * Initialize hash links for nfsnodes 57 * and build nfsnode free list. 58 */ 59 nfs_nhinit() 60 { 61 register int i; 62 register union nhead *nh = nhead; 63 64 #ifndef lint 65 if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 66 panic("nfs_nhinit: too small"); 67 #endif /* not lint */ 68 for (i = NFSNOHSZ; --i >= 0; nh++) { 69 nh->nh_head[0] = nh; 70 nh->nh_head[1] = nh; 71 } 72 } 73 74 /* 75 * Compute an entry in the NFS hash table structure 76 */ 77 union nhead * 78 nfs_hash(fhp) 79 register nfsv2fh_t *fhp; 80 { 81 register u_char *fhpp; 82 register u_long fhsum; 83 int i; 84 85 fhpp = &fhp->fh_bytes[0]; 86 fhsum = 0; 87 for (i = 0; i < NFSX_FH; i++) 88 fhsum += *fhpp++; 89 return (&nhead[NFSNOHASH(fhsum)]); 90 } 91 92 /* 93 * Look up a vnode/nfsnode by file handle. 94 * Callers must check for mount points!! 95 * In all cases, a pointer to a 96 * nfsnode structure is returned. 97 */ 98 nfs_nget(mntp, fhp, npp) 99 struct mount *mntp; 100 register nfsv2fh_t *fhp; 101 struct nfsnode **npp; 102 { 103 register struct nfsnode *np; 104 register struct vnode *vp; 105 extern struct vnodeops nfsv2_vnodeops; 106 struct vnode *nvp; 107 union nhead *nh; 108 int error; 109 110 nh = nfs_hash(fhp); 111 loop: 112 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 113 if (mntp != NFSTOV(np)->v_mount || 114 bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 115 continue; 116 if ((np->n_flag & NLOCKED) != 0) { 117 np->n_flag |= NWANT; 118 (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0); 119 goto loop; 120 } 121 vp = NFSTOV(np); 122 if (vget(vp)) 123 goto loop; 124 *npp = np; 125 return(0); 126 } 127 if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 128 *npp = 0; 129 return (error); 130 } 131 vp = nvp; 132 np = VTONFS(vp); 133 np->n_vnode = vp; 134 /* 135 * Insert the nfsnode in the hash queue for its new file handle 136 */ 137 np->n_flag = 0; 138 insque(np, nh); 139 nfs_lock(vp); 140 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 141 np->n_attrstamp = 0; 142 np->n_direofoffset = 0; 143 np->n_sillyrename = (struct sillyrename *)0; 144 np->n_size = 0; 145 np->n_mtime = 0; 146 *npp = np; 147 return (0); 148 } 149 150 nfs_inactive(vp) 151 struct vnode *vp; 152 { 153 register struct nfsnode *np; 154 register struct nameidata *ndp; 155 register struct sillyrename *sp; 156 struct nfsnode *dnp; 157 extern int prtactive; 158 159 np = VTONFS(vp); 160 if (prtactive && vp->v_usecount != 0) 161 vprint("nfs_inactive: pushing active", vp); 162 nfs_lock(vp); 163 sp = np->n_sillyrename; 164 np->n_sillyrename = (struct sillyrename *)0; 165 if (sp) { 166 /* 167 * Remove the silly file that was rename'd earlier 168 */ 169 ndp = &sp->s_namei; 170 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 171 ndp->ni_dvp = NFSTOV(dnp); 172 nfs_removeit(ndp); 173 nfs_nput(ndp->ni_dvp); 174 } 175 crfree(ndp->ni_cred); 176 free((caddr_t)sp, M_TEMP); 177 } 178 nfs_unlock(vp); 179 np->n_flag &= NMODIFIED; 180 #ifdef notdef 181 /* 182 * Scan the request list for any requests left hanging about 183 */ 184 s = splnet(); 185 rep = nfsreqh.r_next; 186 while (rep && rep != &nfsreqh) { 187 if (rep->r_vp == vp) { 188 rep->r_prev->r_next = rep2 = rep->r_next; 189 rep->r_next->r_prev = rep->r_prev; 190 m_freem(rep->r_mreq); 191 if (rep->r_mrep != NULL) 192 m_freem(rep->r_mrep); 193 free((caddr_t)rep, M_NFSREQ); 194 rep = rep2; 195 } else 196 rep = rep->r_next; 197 } 198 splx(s); 199 #endif 200 return (0); 201 } 202 203 /* 204 * Reclaim an nfsnode so that it can be used for other purposes. 205 */ 206 nfs_reclaim(vp) 207 register struct vnode *vp; 208 { 209 register struct nfsnode *np = VTONFS(vp); 210 extern int prtactive; 211 212 if (prtactive && vp->v_usecount != 0) 213 vprint("nfs_reclaim: pushing active", vp); 214 /* 215 * Remove the nfsnode from its hash chain. 216 */ 217 remque(np); 218 np->n_forw = np; 219 np->n_back = np; 220 cache_purge(vp); 221 np->n_flag = 0; 222 np->n_direofoffset = 0; 223 return (0); 224 } 225 226 /* 227 * Lock an nfsnode 228 */ 229 nfs_lock(vp) 230 struct vnode *vp; 231 { 232 register struct nfsnode *np = VTONFS(vp); 233 234 while (np->n_flag & NLOCKED) { 235 np->n_flag |= NWANT; 236 if (np->n_lockholder == u.u_procp->p_pid) 237 panic("locking against myself"); 238 np->n_lockwaiter = u.u_procp->p_pid; 239 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 240 } 241 np->n_lockwaiter = 0; 242 np->n_lockholder = u.u_procp->p_pid; 243 u.u_spare[0]++; 244 np->n_flag |= NLOCKED; 245 } 246 247 /* 248 * Unlock an nfsnode 249 */ 250 nfs_unlock(vp) 251 struct vnode *vp; 252 { 253 register struct nfsnode *np = VTONFS(vp); 254 255 if ((np->n_flag & NLOCKED) == 0) 256 vprint("nfs_unlock: unlocked nfsnode", vp); 257 np->n_lockholder = 0; 258 u.u_spare[0]--; 259 np->n_flag &= ~NLOCKED; 260 if (np->n_flag & NWANT) { 261 np->n_flag &= ~NWANT; 262 wakeup((caddr_t)np); 263 } 264 } 265 266 /* 267 * Check for a locked nfsnode 268 */ 269 nfs_islocked(vp) 270 struct vnode *vp; 271 { 272 273 if (VTONFS(vp)->n_flag & NLOCKED) 274 return (1); 275 return (0); 276 } 277 278 /* 279 * Unlock and vrele() 280 * since I can't decide if dirs. should be locked, I will check for 281 * the lock and be flexible 282 */ 283 nfs_nput(vp) 284 struct vnode *vp; 285 { 286 register struct nfsnode *np = VTONFS(vp); 287 288 if (np->n_flag & NLOCKED) 289 nfs_unlock(vp); 290 vrele(vp); 291 } 292 293 /* 294 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 295 * done. Currently nothing to do. 296 */ 297 /* ARGSUSED */ 298 nfs_abortop(ndp) 299 struct nameidata *ndp; 300 { 301 302 return (0); 303 } 304