1 /* $NetBSD: coda_subr.c,v 1.12 2001/07/18 16:12:31 thorpej Exp $ */ 2 3 /* 4 * 5 * Coda: an Experimental Distributed File System 6 * Release 3.1 7 * 8 * Copyright (c) 1987-1998 Carnegie Mellon University 9 * All Rights Reserved 10 * 11 * Permission to use, copy, modify and distribute this software and its 12 * documentation is hereby granted, provided that both the copyright 13 * notice and this permission notice appear in all copies of the 14 * software, derivative works or modified versions, and any portions 15 * thereof, and that both notices appear in supporting documentation, and 16 * that credit is given to Carnegie Mellon University in all documents 17 * and publicity pertaining to direct or indirect use of this code or its 18 * derivatives. 19 * 20 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, 21 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS 22 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON 23 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 24 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF 25 * ANY DERIVATIVE WORK. 26 * 27 * Carnegie Mellon encourages users of this software to return any 28 * improvements or extensions that they make, and to grant Carnegie 29 * Mellon the rights to redistribute these changes without encumbrance. 30 * 31 * @(#) coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $ 32 */ 33 34 /* 35 * Mach Operating System 36 * Copyright (c) 1989 Carnegie-Mellon University 37 * All rights reserved. The CMU software License Agreement specifies 38 * the terms and conditions for use and redistribution. 39 */ 40 41 /* 42 * This code was written for the Coda file system at Carnegie Mellon 43 * University. Contributers include David Steere, James Kistler, and 44 * M. Satyanarayanan. */ 45 46 /* NOTES: rvb 47 * 1. Added coda_unmounting to mark all cnodes as being UNMOUNTING. This has to 48 * be done before dounmount is called. Because some of the routines that 49 * dounmount calls before coda_unmounted might try to force flushes to venus. 50 * The vnode pager does this. 51 * 2. coda_unmounting marks all cnodes scanning coda_cache. 52 * 3. cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes 53 * under the /coda mount point. 54 * 4. coda_cacheprint (under DEBUG) prints names with vnode/cnode address 55 */ 56 57 #ifdef _LKM 58 #define NVCODA 4 59 #else 60 #include <vcoda.h> 61 #endif 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/malloc.h> 66 #include <sys/proc.h> 67 #include <sys/select.h> 68 #include <sys/mount.h> 69 70 #include <coda/coda.h> 71 #include <coda/cnode.h> 72 #include <coda/coda_subr.h> 73 #include <coda/coda_namecache.h> 74 75 int coda_active = 0; 76 int coda_reuse = 0; 77 int coda_new = 0; 78 79 struct cnode *coda_freelist = NULL; 80 struct cnode *coda_cache[CODA_CACHESIZE]; 81 82 #define coda_hash(fid) \ 83 (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1)) 84 85 #define CNODE_NEXT(cp) ((cp)->c_next) 86 87 #define ODD(vnode) ((vnode) & 0x1) 88 89 /* 90 * Allocate a cnode. 91 */ 92 struct cnode * 93 coda_alloc(void) 94 { 95 struct cnode *cp; 96 97 if (coda_freelist) { 98 cp = coda_freelist; 99 coda_freelist = CNODE_NEXT(cp); 100 coda_reuse++; 101 } 102 else { 103 CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode)); 104 /* NetBSD vnodes don't have any Pager info in them ('cause there are 105 no external pagers, duh!) */ 106 #define VNODE_VM_INFO_INIT(vp) /* MT */ 107 VNODE_VM_INFO_INIT(CTOV(cp)); 108 coda_new++; 109 } 110 memset(cp, 0, sizeof (struct cnode)); 111 112 return(cp); 113 } 114 115 /* 116 * Deallocate a cnode. 117 */ 118 void 119 coda_free(cp) 120 struct cnode *cp; 121 { 122 123 CNODE_NEXT(cp) = coda_freelist; 124 coda_freelist = cp; 125 } 126 127 /* 128 * Put a cnode in the hash table 129 */ 130 void 131 coda_save(cp) 132 struct cnode *cp; 133 { 134 CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)]; 135 coda_cache[coda_hash(&cp->c_fid)] = cp; 136 } 137 138 /* 139 * Remove a cnode from the hash table 140 */ 141 void 142 coda_unsave(cp) 143 struct cnode *cp; 144 { 145 struct cnode *ptr; 146 struct cnode *ptrprev = NULL; 147 148 ptr = coda_cache[coda_hash(&cp->c_fid)]; 149 while (ptr != NULL) { 150 if (ptr == cp) { 151 if (ptrprev == NULL) { 152 coda_cache[coda_hash(&cp->c_fid)] 153 = CNODE_NEXT(ptr); 154 } else { 155 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr); 156 } 157 CNODE_NEXT(cp) = (struct cnode *)NULL; 158 159 return; 160 } 161 ptrprev = ptr; 162 ptr = CNODE_NEXT(ptr); 163 } 164 } 165 166 /* 167 * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. 168 * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95 169 */ 170 struct cnode * 171 coda_find(fid) 172 ViceFid *fid; 173 { 174 struct cnode *cp; 175 176 cp = coda_cache[coda_hash(fid)]; 177 while (cp) { 178 if ((cp->c_fid.Vnode == fid->Vnode) && 179 (cp->c_fid.Volume == fid->Volume) && 180 (cp->c_fid.Unique == fid->Unique) && 181 (!IS_UNMOUNTING(cp))) 182 { 183 coda_active++; 184 return(cp); 185 } 186 cp = CNODE_NEXT(cp); 187 } 188 return(NULL); 189 } 190 191 /* 192 * coda_kill is called as a side effect to vcopen. To prevent any 193 * cnodes left around from an earlier run of a venus or warden from 194 * causing problems with the new instance, mark any outstanding cnodes 195 * as dying. Future operations on these cnodes should fail (excepting 196 * coda_inactive of course!). Since multiple venii/wardens can be 197 * running, only kill the cnodes for a particular entry in the 198 * coda_mnttbl. -- DCS 12/1/94 */ 199 200 int 201 coda_kill(whoIam, dcstat) 202 struct mount *whoIam; 203 enum dc_status dcstat; 204 { 205 int hash, count = 0; 206 struct cnode *cp; 207 208 /* 209 * Algorithm is as follows: 210 * Second, flush whatever vnodes we can from the name cache. 211 * 212 * Finally, step through whatever is left and mark them dying. 213 * This prevents any operation at all. 214 215 */ 216 217 /* This is slightly overkill, but should work. Eventually it'd be 218 * nice to only flush those entries from the namecache that 219 * reference a vnode in this vfs. */ 220 coda_nc_flush(dcstat); 221 222 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 223 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 224 if (CTOV(cp)->v_mount == whoIam) { 225 #ifdef DEBUG 226 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp); 227 #endif 228 count++; 229 CODADEBUG(CODA_FLUSH, 230 myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n", 231 (cp->c_fid).Volume, 232 (cp->c_fid).Vnode, 233 (cp->c_fid).Unique, 234 cp->c_flags, 235 CTOV(cp)->v_usecount)); ); 236 } 237 } 238 } 239 return count; 240 } 241 242 /* 243 * There are two reasons why a cnode may be in use, it may be in the 244 * name cache or it may be executing. 245 */ 246 void 247 coda_flush(dcstat) 248 enum dc_status dcstat; 249 { 250 int hash; 251 struct cnode *cp; 252 253 coda_clstat.ncalls++; 254 coda_clstat.reqs[CODA_FLUSH]++; 255 256 coda_nc_flush(dcstat); /* flush files from the name cache */ 257 258 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 259 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 260 if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */ 261 coda_vmflush(cp); 262 } 263 } 264 } 265 266 /* 267 * As a debugging measure, print out any cnodes that lived through a 268 * name cache flush. 269 */ 270 void 271 coda_testflush(void) 272 { 273 int hash; 274 struct cnode *cp; 275 276 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 277 for (cp = coda_cache[hash]; 278 cp != NULL; 279 cp = CNODE_NEXT(cp)) { 280 myprintf(("Live cnode fid %lx.%lx.%lx count %d\n", 281 (cp->c_fid).Volume,(cp->c_fid).Vnode, 282 (cp->c_fid).Unique, CTOV(cp)->v_usecount)); 283 } 284 } 285 } 286 287 /* 288 * First, step through all cnodes and mark them unmounting. 289 * NetBSD kernels may try to fsync them now that venus 290 * is dead, which would be a bad thing. 291 * 292 */ 293 void 294 coda_unmounting(whoIam) 295 struct mount *whoIam; 296 { 297 int hash; 298 struct cnode *cp; 299 300 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 301 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 302 if (CTOV(cp)->v_mount == whoIam) { 303 if (cp->c_flags & (C_LOCKED|C_WANTED)) { 304 printf("coda_unmounting: Unlocking %p\n", cp); 305 cp->c_flags &= ~(C_LOCKED|C_WANTED); 306 wakeup((caddr_t) cp); 307 } 308 cp->c_flags |= C_UNMOUNTING; 309 } 310 } 311 } 312 } 313 314 #ifdef DEBUG 315 void 316 coda_checkunmounting(mp) 317 struct mount *mp; 318 { 319 struct vnode *vp, *nvp; 320 struct cnode *cp; 321 int count = 0, bad = 0; 322 loop: 323 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 324 if (vp->v_mount != mp) 325 goto loop; 326 nvp = vp->v_mntvnodes.le_next; 327 cp = VTOC(vp); 328 count++; 329 if (!(cp->c_flags & C_UNMOUNTING)) { 330 bad++; 331 printf("vp %p, cp %p missed\n", vp, cp); 332 cp->c_flags |= C_UNMOUNTING; 333 } 334 } 335 } 336 337 void 338 coda_cacheprint(whoIam) 339 struct mount *whoIam; 340 { 341 int hash; 342 struct cnode *cp; 343 int count = 0; 344 345 printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp)); 346 coda_nc_name(VTOC(coda_ctlvp)); 347 printf("\n"); 348 349 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 350 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 351 if (CTOV(cp)->v_mount == whoIam) { 352 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp); 353 coda_nc_name(cp); 354 printf("\n"); 355 count++; 356 } 357 } 358 } 359 printf("coda_cacheprint: count %d\n", count); 360 } 361 #endif 362 363 /* 364 * There are 6 cases where invalidations occur. The semantics of each 365 * is listed here. 366 * 367 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache. 368 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user 369 * This call is a result of token expiration. 370 * 371 * The next two are the result of callbacks on a file or directory. 372 * CODA_ZAPDIR -- flush the attributes for the dir from its cnode. 373 * Zap all children of this directory from the namecache. 374 * CODA_ZAPFILE -- flush the attributes for a file. 375 * 376 * The fifth is a result of Venus detecting an inconsistent file. 377 * CODA_PURGEFID -- flush the attribute for the file 378 * If it is a dir (odd vnode), purge its 379 * children from the namecache 380 * remove the file from the namecache. 381 * 382 * The sixth allows Venus to replace local fids with global ones 383 * during reintegration. 384 * 385 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 386 */ 387 388 int handleDownCall(opcode, out) 389 int opcode; union outputArgs *out; 390 { 391 int error; 392 393 /* Handle invalidate requests. */ 394 switch (opcode) { 395 case CODA_FLUSH : { 396 397 coda_flush(IS_DOWNCALL); 398 399 CODADEBUG(CODA_FLUSH,coda_testflush();) /* print remaining cnodes */ 400 return(0); 401 } 402 403 case CODA_PURGEUSER : { 404 coda_clstat.ncalls++; 405 coda_clstat.reqs[CODA_PURGEUSER]++; 406 407 /* XXX - need to prevent fsync's */ 408 coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL); 409 return(0); 410 } 411 412 case CODA_ZAPFILE : { 413 struct cnode *cp; 414 415 error = 0; 416 coda_clstat.ncalls++; 417 coda_clstat.reqs[CODA_ZAPFILE]++; 418 419 cp = coda_find(&out->coda_zapfile.CodaFid); 420 if (cp != NULL) { 421 vref(CTOV(cp)); 422 423 cp->c_flags &= ~C_VATTR; 424 if (CTOV(cp)->v_flag & VTEXT) 425 error = coda_vmflush(cp); 426 CODADEBUG(CODA_ZAPFILE, myprintf(( 427 "zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", 428 cp->c_fid.Volume, 429 cp->c_fid.Vnode, 430 cp->c_fid.Unique, 431 CTOV(cp)->v_usecount - 1, error));); 432 if (CTOV(cp)->v_usecount == 1) { 433 cp->c_flags |= C_PURGING; 434 } 435 vrele(CTOV(cp)); 436 } 437 438 return(error); 439 } 440 441 case CODA_ZAPDIR : { 442 struct cnode *cp; 443 444 coda_clstat.ncalls++; 445 coda_clstat.reqs[CODA_ZAPDIR]++; 446 447 cp = coda_find(&out->coda_zapdir.CodaFid); 448 if (cp != NULL) { 449 vref(CTOV(cp)); 450 451 cp->c_flags &= ~C_VATTR; 452 coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL); 453 454 CODADEBUG(CODA_ZAPDIR, myprintf(( 455 "zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n", 456 cp->c_fid.Volume, 457 cp->c_fid.Vnode, 458 cp->c_fid.Unique, 459 CTOV(cp)->v_usecount - 1));); 460 if (CTOV(cp)->v_usecount == 1) { 461 cp->c_flags |= C_PURGING; 462 } 463 vrele(CTOV(cp)); 464 } 465 466 return(0); 467 } 468 469 case CODA_PURGEFID : { 470 struct cnode *cp; 471 472 error = 0; 473 coda_clstat.ncalls++; 474 coda_clstat.reqs[CODA_PURGEFID]++; 475 476 cp = coda_find(&out->coda_purgefid.CodaFid); 477 if (cp != NULL) { 478 vref(CTOV(cp)); 479 if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */ 480 coda_nc_zapParentfid(&out->coda_purgefid.CodaFid, 481 IS_DOWNCALL); 482 } 483 cp->c_flags &= ~C_VATTR; 484 coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL); 485 if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 486 && (CTOV(cp)->v_flag & VTEXT)) { 487 488 error = coda_vmflush(cp); 489 } 490 CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n", 491 cp->c_fid.Volume, cp->c_fid.Vnode, 492 cp->c_fid.Unique, 493 CTOV(cp)->v_usecount - 1, error));); 494 if (CTOV(cp)->v_usecount == 1) { 495 cp->c_flags |= C_PURGING; 496 } 497 vrele(CTOV(cp)); 498 } 499 return(error); 500 } 501 502 case CODA_REPLACE : { 503 struct cnode *cp = NULL; 504 505 coda_clstat.ncalls++; 506 coda_clstat.reqs[CODA_REPLACE]++; 507 508 cp = coda_find(&out->coda_replace.OldFid); 509 if (cp != NULL) { 510 /* remove the cnode from the hash table, replace the fid, and reinsert */ 511 vref(CTOV(cp)); 512 coda_unsave(cp); 513 cp->c_fid = out->coda_replace.NewFid; 514 coda_save(cp); 515 516 CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n", 517 out->coda_replace.OldFid.Volume, 518 out->coda_replace.OldFid.Vnode, 519 out->coda_replace.OldFid.Unique, 520 cp->c_fid.Volume, cp->c_fid.Vnode, 521 cp->c_fid.Unique, cp));) 522 vrele(CTOV(cp)); 523 } 524 return (0); 525 } 526 default: 527 myprintf(("handleDownCall: unknown opcode %d\n", opcode)); 528 return (EINVAL); 529 } 530 } 531 532 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */ 533 534 int 535 coda_vmflush(cp) 536 struct cnode *cp; 537 { 538 return 0; 539 } 540 541 542 /* 543 * kernel-internal debugging switches 544 */ 545 546 void coda_debugon(void) 547 { 548 codadebug = -1; 549 coda_nc_debug = -1; 550 coda_vnop_print_entry = 1; 551 coda_psdev_print_entry = 1; 552 coda_vfsop_print_entry = 1; 553 } 554 555 void coda_debugoff(void) 556 { 557 codadebug = 0; 558 coda_nc_debug = 0; 559 coda_vnop_print_entry = 0; 560 coda_psdev_print_entry = 0; 561 coda_vfsop_print_entry = 0; 562 } 563 564 /* 565 * Utilities used by both client and server 566 * Standard levels: 567 * 0) no debugging 568 * 1) hard failures 569 * 2) soft failures 570 * 3) current test software 571 * 4) main procedure entry points 572 * 5) main procedure exit points 573 * 6) utility procedure entry points 574 * 7) utility procedure exit points 575 * 8) obscure procedure entry points 576 * 9) obscure procedure exit points 577 * 10) random stuff 578 * 11) all <= 1 579 * 12) all <= 2 580 * 13) all <= 3 581 * ... 582 */ 583