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