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 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)nfs_node.c 7.3 (Berkeley) 07/06/89 21 */ 22 23 #include "param.h" 24 #include "systm.h" 25 #include "user.h" 26 #include "proc.h" 27 #include "mount.h" 28 #include "vnode.h" 29 #include "../ufs/dir.h" 30 #include "namei.h" 31 #include "errno.h" 32 #include "nfsv2.h" 33 #include "nfs.h" 34 #include "nfsnode.h" 35 #include "nfsmount.h" 36 #include "kernel.h" 37 #include "malloc.h" 38 39 /* The request list head */ 40 extern struct nfsreq nfsreqh; 41 42 #define NFSNOHSZ 512 43 #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 44 #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 45 #else 46 #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 47 #endif 48 49 union nhead { /* inode LRU cache, Chris Maltby */ 50 union nhead *nh_head[2]; 51 struct nfsnode *nh_chain[2]; 52 } nhead[NFSNOHSZ]; 53 54 struct nfsnode *nfreeh, **nfreet; 55 56 /* 57 * Initialize hash links for nfsnodes 58 * and build nfsnode free list. 59 */ 60 nfs_nhinit() 61 { 62 register int i; 63 register struct nfsnode *np = nfsnode; 64 register union nhead *nh = nhead; 65 66 for (i = NFSNOHSZ; --i >= 0; nh++) { 67 nh->nh_head[0] = nh; 68 nh->nh_head[1] = nh; 69 } 70 nfreeh = np; 71 nfreet = &np->n_freef; 72 np->n_freeb = &nfreeh; 73 np->n_forw = np; 74 np->n_back = np; 75 NFSTOV(np)->v_data = (qaddr_t)np; 76 for (i = nnfsnode; --i > 0; ) { 77 ++np; 78 np->n_forw = np; 79 np->n_back = np; 80 NFSTOV(np)->v_data = (qaddr_t)np; 81 *nfreet = np; 82 np->n_freeb = nfreet; 83 nfreet = &np->n_freef; 84 } 85 np->n_freef = NULL; 86 } 87 88 /* 89 * Look up an vnode/nfsnode by file handle. 90 * Callers must check for mount points!! 91 * In all cases, a pointer to a 92 * nfsnode structure is returned. 93 */ 94 nfs_nget(mntp, fhp, npp) 95 struct mount *mntp; 96 register nfsv2fh_t *fhp; 97 struct nfsnode **npp; 98 { 99 register struct nfsnode *np; 100 register struct vnode *vp; 101 register struct nfsnode *nq; 102 register u_char *fhpp; 103 register u_long fhsum; 104 register int i; 105 union nhead *nh; 106 int error; 107 108 fhpp = &fhp->fh_bytes[0]; 109 fhsum = 0; 110 for (i = 0; i < NFSX_FH; i++) 111 fhsum += *fhpp++; 112 loop: 113 nh = &nhead[NFSNOHASH(fhsum)]; 114 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) 115 if (mntp == NFSTOV(np)->v_mount && 116 !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) { 117 /* 118 * Following is essentially an inline expanded 119 * copy of ngrab(), expanded inline for speed, 120 * and so that the test for a mounted on nfsnode 121 * can be deferred until after we are sure that 122 * the nfsnode isn't busy. 123 */ 124 if ((np->n_flag & NLOCKED) != 0) { 125 np->n_flag |= NWANT; 126 sleep((caddr_t)np, PINOD); 127 goto loop; 128 } 129 vp = NFSTOV(np); 130 if (vp->v_count == 0) { /* nfsno on free list */ 131 if (nq = np->n_freef) 132 nq->n_freeb = np->n_freeb; 133 else 134 nfreet = np->n_freeb; 135 *np->n_freeb = nq; 136 np->n_freef = NULL; 137 np->n_freeb = NULL; 138 } 139 np->n_flag |= NLOCKED; 140 VREF(vp); 141 *npp = np; 142 return(0); 143 } 144 145 if ((np = nfreeh) == NULL) { 146 tablefull("nfsnode"); 147 *npp = 0; 148 return(ENFILE); 149 } 150 vp = NFSTOV(np); 151 if (vp->v_count) 152 panic("free nfsnode isn't"); 153 if (nq = np->n_freef) 154 nq->n_freeb = &nfreeh; 155 nfreeh = nq; 156 np->n_freef = NULL; 157 np->n_freeb = NULL; 158 /* 159 * Now to take nfsnode off the hash chain it was on 160 * (initially, or after an nflush, it is on a "hash chain" 161 * consisting entirely of itself, and pointed to by no-one, 162 * but that doesn't matter), and put it on the chain for 163 * its new file handle 164 */ 165 remque(np); 166 insque(np, nh); 167 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 168 #ifdef notyet 169 cache_purge(vp); 170 #endif 171 np->n_flag = NLOCKED; 172 np->n_attrstamp = 0; 173 np->n_sillyrename = (struct sillyrename *)0; 174 np->n_id = ++nextnfsnodeid; 175 /* 176 * Initialize the associated vnode 177 */ 178 vinit(vp, mntp, VNON, &nfsv2_vnodeops); 179 *npp = np; 180 return (0); 181 } 182 183 /* 184 * Convert a pointer to an nfsnode into a reference to an nfsnode. 185 * 186 * This is basically the internal piece of nget (after the 187 * nfsnode pointer is located) but without the test for mounted 188 * filesystems. It is caller's responsibility to check that 189 * the nfsnode pointer is valid. 190 */ 191 nfs_ngrab(np) 192 register struct nfsnode *np; 193 { 194 register struct vnode *vp = NFSTOV(np); 195 196 while ((np->n_flag & NLOCKED) != 0) { 197 np->n_flag |= NWANT; 198 sleep((caddr_t)np, PINOD); 199 } 200 if (vp->v_count == 0) { /* ino on free list */ 201 register struct nfsnode *nq; 202 203 if (nq = np->n_freef) 204 nq->n_freeb = np->n_freeb; 205 else 206 nfreet = np->n_freeb; 207 *np->n_freeb = nq; 208 np->n_freef = NULL; 209 np->n_freeb = NULL; 210 } 211 VREF(vp); 212 np->n_flag |= NLOCKED; 213 } 214 215 nfs_inactive(vp) 216 struct vnode *vp; 217 { 218 register struct nfsnode *np; 219 register struct nameidata *ndp; 220 register struct sillyrename *sp; 221 register struct nfsreq *rep; 222 struct nfsreq *rep2; 223 struct nfsnode *dnp; 224 int s; 225 226 if (vp == NULL) 227 panic("nfs_inactive NULL vp"); 228 if (vp->v_count == 0) { 229 np = VTONFS(vp); 230 np->n_flag |= NLOCKED; 231 if (np->n_sillyrename) { 232 /* 233 * Remove the silly file that was rename'd earlier 234 */ 235 sp = np->n_sillyrename; 236 ndp = &sp->s_namei; 237 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 238 ndp->ni_dvp = NFSTOV(dnp); 239 if (sp->s_flag == REMOVE) 240 nfs_removeit(ndp); 241 else 242 nfs_rmdirit(ndp); 243 nfs_nput(ndp->ni_dvp); 244 } 245 crfree(ndp->ni_cred); 246 free((caddr_t)sp, M_TEMP); 247 np->n_sillyrename = (struct sillyrename *)0; 248 } 249 nfs_unlock(vp); 250 np->n_flag = 0; 251 /* 252 * Scan the request list for any requests left hanging about 253 */ 254 s = splnet(); 255 rep = nfsreqh.r_next; 256 while (rep) { 257 if (rep->r_vp == vp) { 258 rep->r_prev->r_next = rep2 = rep->r_next; 259 if (rep->r_next != NULL) 260 rep->r_next->r_prev = rep->r_prev; 261 m_freem(rep->r_mreq); 262 if (rep->r_mrep != NULL) 263 m_freem(rep->r_mrep); 264 free((caddr_t)rep, M_NFSREQ); 265 rep = rep2; 266 } else 267 rep = rep->r_next; 268 } 269 splx(s); 270 /* 271 * Put the nfsnode on the end of the free list. 272 */ 273 if (nfreeh) { 274 *nfreet = np; 275 np->n_freeb = nfreet; 276 } else { 277 nfreeh = np; 278 np->n_freeb = &nfreeh; 279 } 280 np->n_freef = NULL; 281 nfreet = &np->n_freef; 282 } 283 return (0); 284 } 285 286 /* 287 * Remove any nfsnodes in the nfsnode cache belonging to mount. 288 * 289 * There should not be any active ones, return error if any are found 290 * (nb: this is a user error, not a system err). 291 */ 292 nfs_nflush(mntp) 293 struct mount *mntp; 294 { 295 register struct nfsnode *np; 296 register struct vnode *vp; 297 298 for (np = nfsnode; np < nfsnodeNNFSNODE; np++) { 299 vp = NFSTOV(np); 300 if (vp->v_mount == mntp) 301 if (vp->v_count) 302 return (EBUSY); 303 else { 304 remque(np); 305 np->n_forw = np; 306 np->n_back = np; 307 /* 308 * as v_count == 0, the inode was on the free 309 * list already, just leave it there, it will 310 * fall off the bottom eventually. We could 311 * perhaps move it to the head of the free 312 * list, but as umounts are done so 313 * infrequently, we would gain very little, 314 * while making the code bigger. 315 */ 316 } 317 } 318 return (0); 319 } 320 321 /* 322 * Lock an nfsnode 323 */ 324 nfs_lock(vp) 325 struct vnode *vp; 326 { 327 register struct nfsnode *np = VTONFS(vp); 328 329 if (np->n_flag & NLOCKED) 330 printf("pid %d hit locked nfsnode=0x%x\n", 331 u.u_procp->p_pid, np); 332 while (np->n_flag & NLOCKED) { 333 np->n_flag |= NWANT; 334 sleep((caddr_t)np, PINOD); 335 } 336 np->n_flag |= NLOCKED; 337 } 338 339 /* 340 * Unlock an nfsnode 341 */ 342 nfs_unlock(vp) 343 struct vnode *vp; 344 { 345 register struct nfsnode *np = VTONFS(vp); 346 347 if ((np->n_flag & NLOCKED) == 0) { 348 printf("pid %d unlocking unlocked nfsnode=0x%x ", 349 u.u_procp->p_pid, np); 350 printf("fh0=0x%x fh1=0x%x fh2=0x%x fh3=0x%x fh4=0x%x fh5=0x%x fh6=0x%x fh7=0x%x\n", 351 np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1], 352 np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3], 353 np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5], 354 np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]); 355 } 356 np->n_flag &= ~NLOCKED; 357 if (np->n_flag & NWANT) { 358 np->n_flag &= ~NWANT; 359 wakeup((caddr_t)np); 360 } 361 } 362 363 /* 364 * Unlock and vrele() 365 * since I can't decide if dirs. should be locked, I will check for 366 * the lock and be flexible 367 */ 368 nfs_nput(vp) 369 struct vnode *vp; 370 { 371 register struct nfsnode *np = VTONFS(vp); 372 373 if (np->n_flag & NLOCKED) 374 nfs_unlock(vp); 375 vrele(vp); 376 } 377 378 nfs_abortop(ndp) 379 register struct nameidata *ndp; 380 { 381 register struct nfsnode *np; 382 383 if (ndp->ni_vp != NULL) { 384 np = VTONFS(ndp->ni_vp); 385 if (np->n_flag & NLOCKED) 386 nfs_unlock(ndp->ni_vp); 387 vrele(ndp->ni_vp); 388 } 389 if (ndp->ni_dvp != NULL) { 390 np = VTONFS(ndp->ni_dvp); 391 if (np->n_flag & NLOCKED) 392 nfs_unlock(ndp->ni_dvp); 393 vrele(ndp->ni_dvp); 394 } 395 } 396 397 /* 398 * This is silly, but if you use a macro and try and use it in a file 399 * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 400 * a good thing 401 */ 402 struct nfsmount *vfs_to_nfs(mp) 403 struct mount *mp; 404 { 405 return ((struct nfsmount *)mp->m_data); 406 } 407