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.31 (Berkeley) 04/16/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 nameidata *ndp; 146 register struct sillyrename *sp; 147 struct nfsnode *dnp; 148 extern int prtactive; 149 150 np = VTONFS(vp); 151 if (prtactive && vp->v_usecount != 0) 152 vprint("nfs_inactive: pushing active", vp); 153 nfs_lock(vp); 154 sp = np->n_sillyrename; 155 np->n_sillyrename = (struct sillyrename *)0; 156 if (sp) { 157 /* 158 * Remove the silly file that was rename'd earlier 159 */ 160 ndp = &sp->s_namei; 161 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 162 ndp->ni_dvp = NFSTOV(dnp); 163 nfs_removeit(ndp, p); 164 nfs_nput(ndp->ni_dvp); 165 } 166 crfree(ndp->ni_cred); 167 free((caddr_t)sp, M_TEMP); 168 } 169 nfs_unlock(vp); 170 np->n_flag &= NMODIFIED; 171 #ifdef notdef 172 /* 173 * Scan the request list for any requests left hanging about 174 */ 175 s = splnet(); 176 rep = nfsreqh.r_next; 177 while (rep && rep != &nfsreqh) { 178 if (rep->r_vp == vp) { 179 rep->r_prev->r_next = rep2 = rep->r_next; 180 rep->r_next->r_prev = rep->r_prev; 181 m_freem(rep->r_mreq); 182 if (rep->r_mrep != NULL) 183 m_freem(rep->r_mrep); 184 free((caddr_t)rep, M_NFSREQ); 185 rep = rep2; 186 } else 187 rep = rep->r_next; 188 } 189 splx(s); 190 #endif 191 return (0); 192 } 193 194 /* 195 * Reclaim an nfsnode so that it can be used for other purposes. 196 */ 197 nfs_reclaim(vp) 198 register struct vnode *vp; 199 { 200 register struct nfsnode *np = VTONFS(vp); 201 extern int prtactive; 202 203 if (prtactive && vp->v_usecount != 0) 204 vprint("nfs_reclaim: pushing active", vp); 205 /* 206 * Remove the nfsnode from its hash chain. 207 */ 208 remque(np); 209 np->n_forw = np; 210 np->n_back = np; 211 cache_purge(vp); 212 np->n_flag = 0; 213 np->n_direofoffset = 0; 214 return (0); 215 } 216 217 /* 218 * Lock an nfsnode 219 */ 220 nfs_lock(vp) 221 struct vnode *vp; 222 { 223 register struct nfsnode *np = VTONFS(vp); 224 225 while (np->n_flag & NLOCKED) { 226 np->n_flag |= NWANT; 227 if (np->n_lockholder == curproc->p_pid) 228 panic("locking against myself"); 229 np->n_lockwaiter = curproc->p_pid; 230 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 231 } 232 np->n_lockwaiter = 0; 233 np->n_lockholder = curproc->p_pid; 234 np->n_flag |= NLOCKED; 235 } 236 237 /* 238 * Unlock an nfsnode 239 */ 240 nfs_unlock(vp) 241 struct vnode *vp; 242 { 243 register struct nfsnode *np = VTONFS(vp); 244 245 if ((np->n_flag & NLOCKED) == 0) 246 vprint("nfs_unlock: unlocked nfsnode", vp); 247 np->n_lockholder = 0; 248 np->n_flag &= ~NLOCKED; 249 if (np->n_flag & NWANT) { 250 np->n_flag &= ~NWANT; 251 wakeup((caddr_t)np); 252 } 253 } 254 255 /* 256 * Check for a locked nfsnode 257 */ 258 nfs_islocked(vp) 259 struct vnode *vp; 260 { 261 262 if (VTONFS(vp)->n_flag & NLOCKED) 263 return (1); 264 return (0); 265 } 266 267 /* 268 * Unlock and vrele() 269 * since I can't decide if dirs. should be locked, I will check for 270 * the lock and be flexible 271 */ 272 nfs_nput(vp) 273 struct vnode *vp; 274 { 275 register struct nfsnode *np = VTONFS(vp); 276 277 if (np->n_flag & NLOCKED) 278 nfs_unlock(vp); 279 vrele(vp); 280 } 281 282 /* 283 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 284 * done. Currently nothing to do. 285 */ 286 /* ARGSUSED */ 287 nfs_abortop(ndp) 288 struct nameidata *ndp; 289 { 290 291 return (0); 292 } 293