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.35 (Berkeley) 12/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 ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode)) 56 printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode)); 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 MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); 123 vp->v_data = np; 124 np->n_vnode = vp; 125 /* 126 * Insert the nfsnode in the hash queue for its new file handle 127 */ 128 np->n_flag = 0; 129 insque(np, nh); 130 nfs_lock(vp); 131 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 132 np->n_attrstamp = 0; 133 np->n_direofoffset = 0; 134 np->n_sillyrename = (struct sillyrename *)0; 135 np->n_size = 0; 136 np->n_mtime = 0; 137 *npp = np; 138 return (0); 139 } 140 141 nfs_inactive(vp, p) 142 struct vnode *vp; 143 struct proc *p; 144 { 145 register struct nfsnode *np; 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 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 161 sp->s_dvp = NFSTOV(dnp); 162 nfs_removeit(sp, p); 163 nfs_nput(sp->s_dvp); 164 } 165 crfree(sp->s_cred); 166 vrele(sp->s_dvp); 167 #ifdef SILLYSEPARATE 168 free((caddr_t)sp, M_NFSREQ); 169 #endif 170 } 171 nfs_unlock(vp); 172 np->n_flag &= NMODIFIED; 173 #ifdef notdef 174 /* 175 * Scan the request list for any requests left hanging about 176 */ 177 s = splnet(); 178 rep = nfsreqh.r_next; 179 while (rep && rep != &nfsreqh) { 180 if (rep->r_vp == vp) { 181 rep->r_prev->r_next = rep2 = rep->r_next; 182 rep->r_next->r_prev = rep->r_prev; 183 m_freem(rep->r_mreq); 184 if (rep->r_mrep != NULL) 185 m_freem(rep->r_mrep); 186 free((caddr_t)rep, M_NFSREQ); 187 rep = rep2; 188 } else 189 rep = rep->r_next; 190 } 191 splx(s); 192 #endif 193 return (0); 194 } 195 196 /* 197 * Reclaim an nfsnode so that it can be used for other purposes. 198 */ 199 nfs_reclaim(vp) 200 register struct vnode *vp; 201 { 202 register struct nfsnode *np = VTONFS(vp); 203 extern int prtactive; 204 205 if (prtactive && vp->v_usecount != 0) 206 vprint("nfs_reclaim: pushing active", vp); 207 /* 208 * Remove the nfsnode from its hash chain. 209 */ 210 remque(np); 211 cache_purge(vp); 212 FREE(vp->v_data, M_NFSNODE); 213 vp->v_data = NULL; 214 return (0); 215 } 216 217 /* 218 * In theory, NFS does not need locking, but we make provision 219 * for doing it just in case it is needed. 220 */ 221 int donfslocking = 0; 222 /* 223 * Lock an nfsnode 224 */ 225 226 nfs_lock(vp) 227 struct vnode *vp; 228 { 229 register struct nfsnode *np = VTONFS(vp); 230 231 if (!donfslocking) 232 return; 233 while (np->n_flag & NLOCKED) { 234 np->n_flag |= NWANT; 235 if (np->n_lockholder == curproc->p_pid) 236 panic("locking against myself"); 237 np->n_lockwaiter = curproc->p_pid; 238 (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 239 } 240 np->n_lockwaiter = 0; 241 np->n_lockholder = curproc->p_pid; 242 np->n_flag |= NLOCKED; 243 } 244 245 /* 246 * Unlock an nfsnode 247 */ 248 nfs_unlock(vp) 249 struct vnode *vp; 250 { 251 register struct nfsnode *np = VTONFS(vp); 252 253 np->n_lockholder = 0; 254 np->n_flag &= ~NLOCKED; 255 if (np->n_flag & NWANT) { 256 np->n_flag &= ~NWANT; 257 wakeup((caddr_t)np); 258 } 259 } 260 261 /* 262 * Check for a locked nfsnode 263 */ 264 nfs_islocked(vp) 265 struct vnode *vp; 266 { 267 268 if (VTONFS(vp)->n_flag & NLOCKED) 269 return (1); 270 return (0); 271 } 272 273 /* 274 * Unlock and vrele() 275 * since I can't decide if dirs. should be locked, I will check for 276 * the lock and be flexible 277 */ 278 nfs_nput(vp) 279 struct vnode *vp; 280 { 281 register struct nfsnode *np = VTONFS(vp); 282 283 if (np->n_flag & NLOCKED) 284 nfs_unlock(vp); 285 vrele(vp); 286 } 287 288 /* 289 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 290 * done. Currently nothing to do. 291 */ 292 /* ARGSUSED */ 293 nfs_abortop(ndp) 294 struct nameidata *ndp; 295 { 296 297 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 298 FREE(ndp->ni_pnbuf, M_NAMEI); 299 return (0); 300 } 301