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.32 (Berkeley) 04/19/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 * Lock an nfsnode 218 */ 219 nfs_lock(vp) 220 struct vnode *vp; 221 { 222 register struct nfsnode *np = VTONFS(vp); 223 224 while (np->n_flag & NLOCKED) { 225 np->n_flag |= NWANT; 226 if (np->n_lockholder == curproc->p_pid) 227 panic("locking against myself"); 228 np->n_lockwaiter = curproc->p_pid; 229 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 230 } 231 np->n_lockwaiter = 0; 232 np->n_lockholder = curproc->p_pid; 233 np->n_flag |= NLOCKED; 234 } 235 236 /* 237 * Unlock an nfsnode 238 */ 239 nfs_unlock(vp) 240 struct vnode *vp; 241 { 242 register struct nfsnode *np = VTONFS(vp); 243 244 if ((np->n_flag & NLOCKED) == 0) 245 vprint("nfs_unlock: unlocked nfsnode", vp); 246 np->n_lockholder = 0; 247 np->n_flag &= ~NLOCKED; 248 if (np->n_flag & NWANT) { 249 np->n_flag &= ~NWANT; 250 wakeup((caddr_t)np); 251 } 252 } 253 254 /* 255 * Check for a locked nfsnode 256 */ 257 nfs_islocked(vp) 258 struct vnode *vp; 259 { 260 261 if (VTONFS(vp)->n_flag & NLOCKED) 262 return (1); 263 return (0); 264 } 265 266 /* 267 * Unlock and vrele() 268 * since I can't decide if dirs. should be locked, I will check for 269 * the lock and be flexible 270 */ 271 nfs_nput(vp) 272 struct vnode *vp; 273 { 274 register struct nfsnode *np = VTONFS(vp); 275 276 if (np->n_flag & NLOCKED) 277 nfs_unlock(vp); 278 vrele(vp); 279 } 280 281 /* 282 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 283 * done. Currently nothing to do. 284 */ 285 /* ARGSUSED */ 286 nfs_abortop(ndp) 287 struct nameidata *ndp; 288 { 289 290 return (0); 291 } 292