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