1 /* $NetBSD: coda_subr.c,v 1.24 2007/10/10 20:42:21 ad 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 #include <sys/cdefs.h> 58 __KERNEL_RCSID(0, "$NetBSD: coda_subr.c,v 1.24 2007/10/10 20:42:21 ad Exp $"); 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/malloc.h> 63 #include <sys/proc.h> 64 #include <sys/select.h> 65 #include <sys/mount.h> 66 67 #include <coda/coda.h> 68 #include <coda/cnode.h> 69 #include <coda/coda_subr.h> 70 #include <coda/coda_namecache.h> 71 72 #ifdef _KERNEL_OPT 73 #include "opt_coda_compat.h" 74 #endif 75 76 int coda_active = 0; 77 int coda_reuse = 0; 78 int coda_new = 0; 79 80 struct cnode *coda_freelist = NULL; 81 struct cnode *coda_cache[CODA_CACHESIZE]; 82 83 #define CNODE_NEXT(cp) ((cp)->c_next) 84 85 #ifdef CODA_COMPAT_5 86 #define coda_hash(fid) \ 87 (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1)) 88 #define IS_DIR(cnode) (cnode.Vnode & 0x1) 89 #else 90 #define coda_hash(fid) \ 91 (coda_f2i(fid) & (CODA_CACHESIZE-1)) 92 #define IS_DIR(cnode) (cnode.opaque[2] & 0x1) 93 #endif 94 95 /* 96 * Allocate a cnode. 97 */ 98 struct cnode * 99 coda_alloc(void) 100 { 101 struct cnode *cp; 102 103 if (coda_freelist) { 104 cp = coda_freelist; 105 coda_freelist = CNODE_NEXT(cp); 106 coda_reuse++; 107 } 108 else { 109 CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode)); 110 /* NetBSD vnodes don't have any Pager info in them ('cause there are 111 no external pagers, duh!) */ 112 #define VNODE_VM_INFO_INIT(vp) /* MT */ 113 VNODE_VM_INFO_INIT(CTOV(cp)); 114 coda_new++; 115 } 116 memset(cp, 0, sizeof (struct cnode)); 117 118 return(cp); 119 } 120 121 /* 122 * Deallocate a cnode. 123 */ 124 void 125 coda_free(struct cnode *cp) 126 { 127 128 CNODE_NEXT(cp) = coda_freelist; 129 coda_freelist = cp; 130 } 131 132 /* 133 * Put a cnode in the hash table 134 */ 135 void 136 coda_save(struct cnode *cp) 137 { 138 CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)]; 139 coda_cache[coda_hash(&cp->c_fid)] = cp; 140 } 141 142 /* 143 * Remove a cnode from the hash table 144 */ 145 void 146 coda_unsave(struct cnode *cp) 147 { 148 struct cnode *ptr; 149 struct cnode *ptrprev = NULL; 150 151 ptr = coda_cache[coda_hash(&cp->c_fid)]; 152 while (ptr != NULL) { 153 if (ptr == cp) { 154 if (ptrprev == NULL) { 155 coda_cache[coda_hash(&cp->c_fid)] 156 = CNODE_NEXT(ptr); 157 } else { 158 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr); 159 } 160 CNODE_NEXT(cp) = (struct cnode *)NULL; 161 162 return; 163 } 164 ptrprev = ptr; 165 ptr = CNODE_NEXT(ptr); 166 } 167 } 168 169 /* 170 * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it. 171 * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95 172 */ 173 struct cnode * 174 coda_find(CodaFid *fid) 175 { 176 struct cnode *cp; 177 178 cp = coda_cache[coda_hash(fid)]; 179 while (cp) { 180 if (coda_fid_eq(&(cp->c_fid), fid) && 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(struct mount *whoIam, enum dc_status dcstat) 202 { 203 int hash, count = 0; 204 struct cnode *cp; 205 206 /* 207 * Algorithm is as follows: 208 * Second, flush whatever vnodes we can from the name cache. 209 * 210 * Finally, step through whatever is left and mark them dying. 211 * This prevents any operation at all. 212 213 */ 214 215 /* This is slightly overkill, but should work. Eventually it'd be 216 * nice to only flush those entries from the namecache that 217 * reference a vnode in this vfs. */ 218 coda_nc_flush(dcstat); 219 220 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 221 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 222 if (CTOV(cp)->v_mount == whoIam) { 223 #ifdef DEBUG 224 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp); 225 #endif 226 count++; 227 CODADEBUG(CODA_FLUSH, 228 myprintf(("Live cnode fid %s flags %d count %d\n", 229 coda_f2s(&cp->c_fid), 230 cp->c_flags, 231 CTOV(cp)->v_usecount)); ); 232 } 233 } 234 } 235 return count; 236 } 237 238 /* 239 * There are two reasons why a cnode may be in use, it may be in the 240 * name cache or it may be executing. 241 */ 242 void 243 coda_flush(enum dc_status dcstat) 244 { 245 int hash; 246 struct cnode *cp; 247 248 coda_clstat.ncalls++; 249 coda_clstat.reqs[CODA_FLUSH]++; 250 251 coda_nc_flush(dcstat); /* flush files from the name cache */ 252 253 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 254 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 255 if (!IS_DIR(cp->c_fid)) /* only files can be executed */ 256 coda_vmflush(cp); 257 } 258 } 259 } 260 261 /* 262 * As a debugging measure, print out any cnodes that lived through a 263 * name cache flush. 264 */ 265 void 266 coda_testflush(void) 267 { 268 int hash; 269 struct cnode *cp; 270 271 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 272 for (cp = coda_cache[hash]; 273 cp != NULL; 274 cp = CNODE_NEXT(cp)) { 275 myprintf(("Live cnode fid %s count %d\n", 276 coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); 277 } 278 } 279 } 280 281 /* 282 * First, step through all cnodes and mark them unmounting. 283 * NetBSD kernels may try to fsync them now that venus 284 * is dead, which would be a bad thing. 285 * 286 */ 287 void 288 coda_unmounting(struct mount *whoIam) 289 { 290 int hash; 291 struct cnode *cp; 292 293 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 294 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 295 if (CTOV(cp)->v_mount == whoIam) { 296 if (cp->c_flags & (C_LOCKED|C_WANTED)) { 297 printf("coda_unmounting: Unlocking %p\n", cp); 298 cp->c_flags &= ~(C_LOCKED|C_WANTED); 299 wakeup((void *) cp); 300 } 301 cp->c_flags |= C_UNMOUNTING; 302 } 303 } 304 } 305 } 306 307 #ifdef DEBUG 308 void 309 coda_checkunmounting(struct mount *mp) 310 { 311 struct vnode *vp; 312 struct cnode *cp; 313 int count = 0, bad = 0; 314 loop: 315 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 316 if (vp->v_mount != mp) 317 goto loop; 318 cp = VTOC(vp); 319 count++; 320 if (!(cp->c_flags & C_UNMOUNTING)) { 321 bad++; 322 printf("vp %p, cp %p missed\n", vp, cp); 323 cp->c_flags |= C_UNMOUNTING; 324 } 325 } 326 } 327 328 void 329 coda_cacheprint(struct mount *whoIam) 330 { 331 int hash; 332 struct cnode *cp; 333 int count = 0; 334 335 printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp)); 336 coda_nc_name(VTOC(coda_ctlvp)); 337 printf("\n"); 338 339 for (hash = 0; hash < CODA_CACHESIZE; hash++) { 340 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) { 341 if (CTOV(cp)->v_mount == whoIam) { 342 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp); 343 coda_nc_name(cp); 344 printf("\n"); 345 count++; 346 } 347 } 348 } 349 printf("coda_cacheprint: count %d\n", count); 350 } 351 #endif 352 353 /* 354 * There are 6 cases where invalidations occur. The semantics of each 355 * is listed here. 356 * 357 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache. 358 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user 359 * This call is a result of token expiration. 360 * 361 * The next two are the result of callbacks on a file or directory. 362 * CODA_ZAPDIR -- flush the attributes for the dir from its cnode. 363 * Zap all children of this directory from the namecache. 364 * CODA_ZAPFILE -- flush the attributes for a file. 365 * 366 * The fifth is a result of Venus detecting an inconsistent file. 367 * CODA_PURGEFID -- flush the attribute for the file 368 * If it is a dir (odd vnode), purge its 369 * children from the namecache 370 * remove the file from the namecache. 371 * 372 * The sixth allows Venus to replace local fids with global ones 373 * during reintegration. 374 * 375 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache 376 */ 377 378 int handleDownCall(int opcode, union outputArgs *out) 379 { 380 int error; 381 382 /* Handle invalidate requests. */ 383 switch (opcode) { 384 case CODA_FLUSH : { 385 386 coda_flush(IS_DOWNCALL); 387 388 CODADEBUG(CODA_FLUSH,coda_testflush();) /* print remaining cnodes */ 389 return(0); 390 } 391 392 case CODA_PURGEUSER : { 393 coda_clstat.ncalls++; 394 coda_clstat.reqs[CODA_PURGEUSER]++; 395 396 /* XXX - need to prevent fsync's */ 397 #ifdef CODA_COMPAT_5 398 coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL); 399 #else 400 coda_nc_purge_user(out->coda_purgeuser.uid, IS_DOWNCALL); 401 #endif 402 return(0); 403 } 404 405 case CODA_ZAPFILE : { 406 struct cnode *cp; 407 408 error = 0; 409 coda_clstat.ncalls++; 410 coda_clstat.reqs[CODA_ZAPFILE]++; 411 412 cp = coda_find(&out->coda_zapfile.Fid); 413 if (cp != NULL) { 414 vref(CTOV(cp)); 415 416 cp->c_flags &= ~C_VATTR; 417 if (CTOV(cp)->v_iflag & VI_TEXT) 418 error = coda_vmflush(cp); 419 CODADEBUG(CODA_ZAPFILE, myprintf(( 420 "zapfile: fid = %s, refcnt = %d, error = %d\n", 421 coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error));); 422 if (CTOV(cp)->v_usecount == 1) { 423 cp->c_flags |= C_PURGING; 424 } 425 vrele(CTOV(cp)); 426 } 427 428 return(error); 429 } 430 431 case CODA_ZAPDIR : { 432 struct cnode *cp; 433 434 coda_clstat.ncalls++; 435 coda_clstat.reqs[CODA_ZAPDIR]++; 436 437 cp = coda_find(&out->coda_zapdir.Fid); 438 if (cp != NULL) { 439 vref(CTOV(cp)); 440 441 cp->c_flags &= ~C_VATTR; 442 coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL); 443 444 CODADEBUG(CODA_ZAPDIR, myprintf(( 445 "zapdir: fid = %s, refcnt = %d\n", 446 coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1));); 447 if (CTOV(cp)->v_usecount == 1) { 448 cp->c_flags |= C_PURGING; 449 } 450 vrele(CTOV(cp)); 451 } 452 453 return(0); 454 } 455 456 case CODA_PURGEFID : { 457 struct cnode *cp; 458 459 error = 0; 460 coda_clstat.ncalls++; 461 coda_clstat.reqs[CODA_PURGEFID]++; 462 463 cp = coda_find(&out->coda_purgefid.Fid); 464 if (cp != NULL) { 465 vref(CTOV(cp)); 466 if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */ 467 coda_nc_zapParentfid(&out->coda_purgefid.Fid, 468 IS_DOWNCALL); 469 } 470 cp->c_flags &= ~C_VATTR; 471 coda_nc_zapfid(&out->coda_purgefid.Fid, IS_DOWNCALL); 472 if (!(IS_DIR(out->coda_purgefid.Fid)) 473 && (CTOV(cp)->v_iflag & VI_TEXT)) { 474 475 error = coda_vmflush(cp); 476 } 477 CODADEBUG(CODA_PURGEFID, myprintf(( 478 "purgefid: fid = %s, refcnt = %d, error = %d\n", 479 coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error));); 480 if (CTOV(cp)->v_usecount == 1) { 481 cp->c_flags |= C_PURGING; 482 } 483 vrele(CTOV(cp)); 484 } 485 return(error); 486 } 487 488 case CODA_REPLACE : { 489 struct cnode *cp = NULL; 490 491 coda_clstat.ncalls++; 492 coda_clstat.reqs[CODA_REPLACE]++; 493 494 cp = coda_find(&out->coda_replace.OldFid); 495 if (cp != NULL) { 496 /* remove the cnode from the hash table, replace the fid, and reinsert */ 497 vref(CTOV(cp)); 498 coda_unsave(cp); 499 cp->c_fid = out->coda_replace.NewFid; 500 coda_save(cp); 501 502 CODADEBUG(CODA_REPLACE, myprintf(( 503 "replace: oldfid = %s, newfid = %s, cp = %p\n", 504 coda_f2s(&out->coda_replace.OldFid), 505 coda_f2s(&cp->c_fid), cp));) 506 vrele(CTOV(cp)); 507 } 508 return (0); 509 } 510 default: 511 myprintf(("handleDownCall: unknown opcode %d\n", opcode)); 512 return (EINVAL); 513 } 514 } 515 516 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */ 517 518 int 519 coda_vmflush(struct cnode *cp) 520 { 521 return 0; 522 } 523 524 525 /* 526 * kernel-internal debugging switches 527 */ 528 529 void coda_debugon(void) 530 { 531 codadebug = -1; 532 coda_nc_debug = -1; 533 coda_vnop_print_entry = 1; 534 coda_psdev_print_entry = 1; 535 coda_vfsop_print_entry = 1; 536 } 537 538 void coda_debugoff(void) 539 { 540 codadebug = 0; 541 coda_nc_debug = 0; 542 coda_vnop_print_entry = 0; 543 coda_psdev_print_entry = 0; 544 coda_vfsop_print_entry = 0; 545 } 546 547 /* 548 * Utilities used by both client and server 549 * Standard levels: 550 * 0) no debugging 551 * 1) hard failures 552 * 2) soft failures 553 * 3) current test software 554 * 4) main procedure entry points 555 * 5) main procedure exit points 556 * 6) utility procedure entry points 557 * 7) utility procedure exit points 558 * 8) obscure procedure entry points 559 * 9) obscure procedure exit points 560 * 10) random stuff 561 * 11) all <= 1 562 * 12) all <= 2 563 * 13) all <= 3 564 * ... 565 */ 566