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.4 (Berkeley) 08/30/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 #define TRUE 1 57 #define FALSE 0 58 59 /* 60 * Initialize hash links for nfsnodes 61 * and build nfsnode free list. 62 */ 63 nfs_nhinit() 64 { 65 register int i; 66 register struct nfsnode *np = nfsnode; 67 register union nhead *nh = nhead; 68 69 for (i = NFSNOHSZ; --i >= 0; nh++) { 70 nh->nh_head[0] = nh; 71 nh->nh_head[1] = nh; 72 } 73 nfreeh = np; 74 nfreet = &np->n_freef; 75 np->n_freeb = &nfreeh; 76 np->n_forw = np; 77 np->n_back = np; 78 NFSTOV(np)->v_data = (qaddr_t)np; 79 NFSTOV(np)->v_type = VNON; 80 for (i = nnfsnode; --i > 0; ) { 81 ++np; 82 np->n_forw = np; 83 np->n_back = np; 84 NFSTOV(np)->v_data = (qaddr_t)np; 85 NFSTOV(np)->v_type = VNON; 86 *nfreet = np; 87 np->n_freeb = nfreet; 88 nfreet = &np->n_freef; 89 } 90 np->n_freef = NULL; 91 } 92 93 /* 94 * Look up an vnode/nfsnode by file handle. 95 * Callers must check for mount points!! 96 * In all cases, a pointer to a 97 * nfsnode structure is returned. 98 */ 99 nfs_nget(mntp, fhp, npp) 100 struct mount *mntp; 101 register nfsv2fh_t *fhp; 102 struct nfsnode **npp; 103 { 104 register struct nfsnode *np; 105 register struct vnode *vp; 106 register struct nfsnode *nq; 107 register u_char *fhpp; 108 register u_long fhsum; 109 register int i; 110 union nhead *nh; 111 int error; 112 113 fhpp = &fhp->fh_bytes[0]; 114 fhsum = 0; 115 for (i = 0; i < NFSX_FH; i++) 116 fhsum += *fhpp++; 117 loop: 118 nh = &nhead[NFSNOHASH(fhsum)]; 119 for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 120 if (mntp == NFSTOV(np)->v_mount && 121 !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) { 122 /* 123 * Following is essentially an inline expanded 124 * copy of ngrab(), expanded inline for speed, 125 * and so that the test for a mounted on nfsnode 126 * can be deferred until after we are sure that 127 * the nfsnode isn't busy. 128 */ 129 if ((np->n_flag & NLOCKED) != 0) { 130 np->n_flag |= NWANT; 131 sleep((caddr_t)np, PINOD); 132 goto loop; 133 } 134 vp = NFSTOV(np); 135 if (vp->v_count == 0) { /* nfsno on free list */ 136 if (nq = np->n_freef) 137 nq->n_freeb = np->n_freeb; 138 else 139 nfreet = np->n_freeb; 140 *np->n_freeb = nq; 141 np->n_freef = NULL; 142 np->n_freeb = NULL; 143 } 144 np->n_flag |= NLOCKED; 145 VREF(vp); 146 *npp = np; 147 return(0); 148 } 149 150 } 151 if ((np = nfreeh) == NULL) { 152 tablefull("nfsnode"); 153 *npp = 0; 154 return(ENFILE); 155 } 156 vp = NFSTOV(np); 157 if (vp->v_count) 158 panic("free nfsnode isn't"); 159 if (nq = np->n_freef) 160 nq->n_freeb = &nfreeh; 161 nfreeh = nq; 162 np->n_freef = NULL; 163 np->n_freeb = NULL; 164 /* 165 * Now to take nfsnode off the hash chain it was on 166 * (initially, or after an nflush, it is on a "hash chain" 167 * consisting entirely of itself, and pointed to by no-one, 168 * but that doesn't matter) 169 */ 170 remque(np); 171 /* 172 * Flush out any associated bio buffers that might be lying about 173 */ 174 if (vp->v_type == VREG && (np->n_flag & NMODIFIED) == 0) { 175 np->n_flag |= NLOCKED; 176 nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 177 } 178 /* 179 * Insert the nfsnode in the hash queue for its new file handle 180 */ 181 np->n_flag = NLOCKED; 182 insque(np, nh); 183 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 184 #ifndef notyet 185 cache_purge(vp); 186 #endif 187 np->n_attrstamp = 0; 188 np->n_sillyrename = (struct sillyrename *)0; 189 np->n_id = ++nextnfsnodeid; 190 np->n_size = 0; 191 np->n_mtime = 0; 192 /* 193 * Initialize the associated vnode 194 */ 195 vinit(vp, mntp, VNON, &nfsv2_vnodeops); 196 *npp = np; 197 return (0); 198 } 199 200 /* 201 * Convert a pointer to an nfsnode into a reference to an nfsnode. 202 * 203 * This is basically the internal piece of nget (after the 204 * nfsnode pointer is located) but without the test for mounted 205 * filesystems. It is caller's responsibility to check that 206 * the nfsnode pointer is valid. 207 */ 208 nfs_ngrab(np) 209 register struct nfsnode *np; 210 { 211 register struct vnode *vp = NFSTOV(np); 212 213 while ((np->n_flag & NLOCKED) != 0) { 214 np->n_flag |= NWANT; 215 sleep((caddr_t)np, PINOD); 216 } 217 if (vp->v_count == 0) { /* ino on free list */ 218 register struct nfsnode *nq; 219 220 if (nq = np->n_freef) 221 nq->n_freeb = np->n_freeb; 222 else 223 nfreet = np->n_freeb; 224 *np->n_freeb = nq; 225 np->n_freef = NULL; 226 np->n_freeb = NULL; 227 } 228 VREF(vp); 229 np->n_flag |= NLOCKED; 230 } 231 232 nfs_inactive(vp) 233 struct vnode *vp; 234 { 235 register struct nfsnode *np; 236 register struct nameidata *ndp; 237 register struct sillyrename *sp; 238 register struct nfsreq *rep; 239 struct nfsreq *rep2; 240 struct nfsnode *dnp; 241 int s; 242 243 if (vp == NULL) 244 panic("nfs_inactive NULL vp"); 245 if (vp->v_count == 0) { 246 np = VTONFS(vp); 247 sp = np->n_sillyrename; 248 np->n_sillyrename = (struct sillyrename *)0; 249 nfs_lock(vp); 250 if (sp) { 251 printf("in silltren inact\n"); 252 /* 253 * Remove the silly file that was rename'd earlier 254 */ 255 ndp = &sp->s_namei; 256 if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 257 printf("got the dir\n"); 258 ndp->ni_dvp = NFSTOV(dnp); 259 nfs_removeit(ndp); 260 nfs_nput(ndp->ni_dvp); 261 } 262 crfree(ndp->ni_cred); 263 free((caddr_t)sp, M_TEMP); 264 } 265 nfs_unlock(vp); 266 np->n_flag = 0; 267 #ifdef notdef 268 /* 269 * Scan the request list for any requests left hanging about 270 */ 271 s = splnet(); 272 rep = nfsreqh.r_next; 273 while (rep) { 274 if (rep->r_vp == vp) { 275 rep->r_prev->r_next = rep2 = rep->r_next; 276 if (rep->r_next != NULL) 277 rep->r_next->r_prev = rep->r_prev; 278 m_freem(rep->r_mreq); 279 if (rep->r_mrep != NULL) 280 m_freem(rep->r_mrep); 281 free((caddr_t)rep, M_NFSREQ); 282 rep = rep2; 283 } else 284 rep = rep->r_next; 285 } 286 splx(s); 287 #endif 288 /* 289 * Put the nfsnode on the end of the free list. 290 */ 291 if (nfreeh) { 292 *nfreet = np; 293 np->n_freeb = nfreet; 294 } else { 295 nfreeh = np; 296 np->n_freeb = &nfreeh; 297 } 298 np->n_freef = NULL; 299 nfreet = &np->n_freef; 300 } 301 return (0); 302 } 303 304 /* 305 * Remove any nfsnodes in the nfsnode cache belonging to mount. 306 * 307 * There should not be any active ones, return error if any are found 308 * (nb: this is a user error, not a system err). 309 */ 310 nfs_nflush(mntp) 311 struct mount *mntp; 312 { 313 register struct nfsnode *np; 314 register struct vnode *vp; 315 316 for (np = nfsnode; np < nfsnodeNNFSNODE; np++) { 317 vp = NFSTOV(np); 318 if (vp->v_mount == mntp) 319 if (vp->v_count) 320 return (EBUSY); 321 else { 322 remque(np); 323 np->n_forw = np; 324 np->n_back = np; 325 /* 326 * as v_count == 0, the inode was on the free 327 * list already, just leave it there, it will 328 * fall off the bottom eventually. We could 329 * perhaps move it to the head of the free 330 * list, but as umounts are done so 331 * infrequently, we would gain very little, 332 * while making the code bigger. 333 */ 334 } 335 } 336 return (0); 337 } 338 339 /* 340 * Lock an nfsnode 341 */ 342 nfs_lock(vp) 343 struct vnode *vp; 344 { 345 register struct nfsnode *np = VTONFS(vp); 346 347 if (np->n_flag & NLOCKED) 348 printf("pid %d hit locked nfsnode=0x%x\n", 349 u.u_procp->p_pid, np); 350 while (np->n_flag & NLOCKED) { 351 np->n_flag |= NWANT; 352 sleep((caddr_t)np, PINOD); 353 } 354 np->n_flag |= NLOCKED; 355 } 356 357 /* 358 * Unlock an nfsnode 359 */ 360 nfs_unlock(vp) 361 struct vnode *vp; 362 { 363 register struct nfsnode *np = VTONFS(vp); 364 365 if ((np->n_flag & NLOCKED) == 0) { 366 printf("pid %d unlocking unlocked nfsnode=0x%x ", 367 u.u_procp->p_pid, np); 368 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", 369 np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1], 370 np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3], 371 np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5], 372 np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]); 373 } 374 np->n_flag &= ~NLOCKED; 375 if (np->n_flag & NWANT) { 376 np->n_flag &= ~NWANT; 377 wakeup((caddr_t)np); 378 } 379 } 380 381 /* 382 * Unlock and vrele() 383 * since I can't decide if dirs. should be locked, I will check for 384 * the lock and be flexible 385 */ 386 nfs_nput(vp) 387 struct vnode *vp; 388 { 389 register struct nfsnode *np = VTONFS(vp); 390 391 if (np->n_flag & NLOCKED) 392 nfs_unlock(vp); 393 vrele(vp); 394 } 395 396 nfs_abortop(ndp) 397 register struct nameidata *ndp; 398 { 399 register struct nfsnode *np; 400 401 if (ndp->ni_vp != NULL) { 402 np = VTONFS(ndp->ni_vp); 403 if (np->n_flag & NLOCKED) 404 nfs_unlock(ndp->ni_vp); 405 vrele(ndp->ni_vp); 406 } 407 if (ndp->ni_dvp != NULL) { 408 np = VTONFS(ndp->ni_dvp); 409 if (np->n_flag & NLOCKED) 410 nfs_unlock(ndp->ni_dvp); 411 vrele(ndp->ni_dvp); 412 } 413 } 414 415 /* 416 * This is silly, but if you use a macro and try and use it in a file 417 * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 418 * a good thing 419 */ 420 struct nfsmount *vfs_to_nfs(mp) 421 struct mount *mp; 422 { 423 return ((struct nfsmount *)mp->m_data); 424 } 425