1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)map.c 1.2 (Berkeley) 6/25/91 13 * 14 * $Id: map.c,v 5.2.2.1 1992/02/09 15:08:36 jsp beta $ 15 * 16 */ 17 18 #include "am.h" 19 20 /* 21 * Generation Numbers. 22 * 23 * Generation numbers are allocated to every node created 24 * by amd. When a filehandle is computed and sent to the 25 * kernel, the generation number makes sure that it is safe 26 * to reallocate a node slot even when the kernel has a cached 27 * reference to its old incarnation. 28 * No garbage collection is done, since it is assumed that 29 * there is no way that 2^32 generation numbers could ever 30 * be allocated by a single run of amd - there is simply 31 * not enough cpu time available. 32 */ 33 static unsigned int am_gen = 2; /* Initial generation number */ 34 #define new_gen() (am_gen++) 35 36 am_node **exported_ap = (am_node **) 0; 37 int exported_ap_size = 0; 38 int first_free_map = 0; /* First available free slot */ 39 int last_used_map = -1; /* Last unavailable used slot */ 40 static int timeout_mp_id; /* Id from last call to timeout */ 41 42 /* 43 * This is the default attributes field which 44 * is copied into every new node to be created. 45 * The individual filesystem fs_init() routines 46 * patch the copy to represent the particular 47 * details for the relevant filesystem type 48 */ 49 static struct fattr gen_fattr = { 50 NFLNK, /* type */ 51 NFSMODE_LNK | 0777, /* mode */ 52 1, /* nlink */ 53 0, /* uid */ 54 0, /* gid */ 55 0, /* size */ 56 4096, /* blocksize */ 57 0, /* rdev */ 58 1, /* blocks */ 59 0, /* fsid */ 60 0, /* fileid */ 61 { 0, 0 }, /* atime */ 62 { 0, 0 }, /* mtime */ 63 { 0, 0 }, /* ctime */ 64 }; 65 66 /* 67 * Resize exported_ap map 68 */ 69 static int exported_ap_realloc_map P((int nsize)); 70 static int exported_ap_realloc_map(nsize) 71 int nsize; 72 { 73 #ifdef notdef 74 /* 75 * If a second realloc occasionally causes Amd to die 76 * in then include this check. 77 */ 78 if (exported_ap_size != 0) /* XXX */ 79 return 0; 80 #endif 81 82 /* 83 * this shouldn't happen, but... 84 */ 85 if (nsize < 0 || nsize == exported_ap_size) 86 return 0; 87 88 exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node*)); 89 90 if (nsize > exported_ap_size) 91 bzero((char*) (exported_ap+exported_ap_size), 92 (nsize - exported_ap_size) * sizeof(am_node*)); 93 exported_ap_size = nsize; 94 95 return 1; 96 } 97 98 99 /* 100 * The root of the mount tree. 101 */ 102 am_node *root_node; 103 104 /* 105 * Allocate a new mount slot and create 106 * a new node. 107 * Fills in the map number of the node, 108 * but leaves everything else uninitialised. 109 */ 110 am_node *exported_ap_alloc(P_void) 111 { 112 am_node *mp, **mpp; 113 114 /* 115 * First check if there are any slots left, realloc if needed 116 */ 117 if (first_free_map >= exported_ap_size) 118 if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP)) 119 return 0; 120 121 /* 122 * Grab the next free slot 123 */ 124 mpp = exported_ap + first_free_map; 125 mp = *mpp = ALLOC(am_node); 126 bzero((char *) mp, sizeof(*mp)); 127 128 mp->am_mapno = first_free_map++; 129 130 /* 131 * Update free pointer 132 */ 133 while (first_free_map < exported_ap_size && exported_ap[first_free_map]) 134 first_free_map++; 135 136 if (first_free_map > last_used_map) 137 last_used_map = first_free_map - 1; 138 139 /* 140 * Shrink exported_ap if reasonable 141 */ 142 if (last_used_map < exported_ap_size - (NEXP_AP + NEXP_AP_MARGIN)) 143 exported_ap_realloc_map(exported_ap_size - NEXP_AP); 144 145 #ifdef DEBUG 146 /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n", 147 last_used_map, first_free_map);*/ 148 #endif /* DEBUG */ 149 150 return mp; 151 } 152 153 /* 154 * Free a mount slot 155 */ 156 void exported_ap_free P((am_node *mp)); 157 void exported_ap_free(mp) 158 am_node *mp; 159 { 160 /* 161 * Sanity check 162 */ 163 if (!mp) 164 return; 165 166 /* 167 * Zero the slot pointer to avoid double free's 168 */ 169 exported_ap[mp->am_mapno] = 0; 170 171 /* 172 * Update the free and last_used indices 173 */ 174 if (mp->am_mapno == last_used_map) 175 while (last_used_map >= 0 && exported_ap[last_used_map] == 0) 176 --last_used_map; 177 178 if (first_free_map > mp->am_mapno) 179 first_free_map = mp->am_mapno; 180 181 #ifdef DEBUG 182 /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n", 183 last_used_map, first_free_map);*/ 184 #endif /* DEBUG */ 185 186 /* 187 * Free the mount node 188 */ 189 free((voidp) mp); 190 } 191 192 /* 193 * Insert mp into the correct place, 194 * where p_mp is its parent node. 195 * A new node gets placed as the youngest sibling 196 * of any other children, and the parent's child 197 * pointer is adjusted to point to the new child node. 198 */ 199 void insert_am(mp, p_mp) 200 am_node *mp; 201 am_node *p_mp; 202 { 203 /* 204 * If this is going in at the root then flag it 205 * so that it cannot be unmounted by amq. 206 */ 207 if (p_mp == root_node) 208 mp->am_flags |= AMF_ROOT; 209 /* 210 * Fill in n-way links 211 */ 212 mp->am_parent = p_mp; 213 mp->am_osib = p_mp->am_child; 214 if (mp->am_osib) 215 mp->am_osib->am_ysib = mp; 216 p_mp->am_child = mp; 217 } 218 219 /* 220 * Remove am from its place in the mount tree 221 */ 222 void remove_am(mp) 223 am_node *mp; 224 { 225 /* 226 * 1. Consistency check 227 */ 228 if (mp->am_child && mp->am_parent) { 229 plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path); 230 } 231 232 /* 233 * 2. Update parent's child pointer 234 */ 235 if (mp->am_parent && mp->am_parent->am_child == mp) 236 mp->am_parent->am_child = mp->am_osib; 237 238 /* 239 * 3. Unlink from sibling chain 240 */ 241 if (mp->am_ysib) 242 mp->am_ysib->am_osib = mp->am_osib; 243 if (mp->am_osib) 244 mp->am_osib->am_ysib = mp->am_ysib; 245 } 246 247 /* 248 * Compute a new time to live value for a node. 249 */ 250 void new_ttl(mp) 251 am_node *mp; 252 { 253 mp->am_timeo_w = 0; 254 255 mp->am_ttl = clocktime(); 256 mp->am_fattr.atime.seconds = mp->am_ttl; 257 mp->am_ttl += mp->am_timeo; /* sun's -tl option */ 258 } 259 260 void mk_fattr P((am_node *mp, ftype vntype)); 261 void mk_fattr(mp, vntype) 262 am_node *mp; 263 ftype vntype; 264 { 265 switch (vntype) { 266 case NFDIR: 267 mp->am_fattr.type = NFDIR; 268 mp->am_fattr.mode = NFSMODE_DIR | 0555; 269 mp->am_fattr.nlink = 2; 270 mp->am_fattr.size = 512; 271 break; 272 case NFLNK: 273 mp->am_fattr.type = NFLNK; 274 mp->am_fattr.mode = NFSMODE_LNK | 0777; 275 mp->am_fattr.nlink = 1; 276 mp->am_fattr.size = 0; 277 break; 278 default: 279 plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype); 280 break; 281 } 282 } 283 284 /* 285 * Initialise an allocated mount node. 286 * It is assumed that the mount node was bzero'd 287 * before getting here so anything that would 288 * be set to zero isn't done here. 289 */ 290 void init_map(mp, dir) 291 am_node *mp; 292 char *dir; 293 { 294 /* mp->am_mapno initalised by exported_ap_alloc */ 295 mp->am_mnt = new_mntfs(); 296 mp->am_name = strdup(dir); 297 mp->am_path = strdup(dir); 298 /*mp->am_link = 0;*/ 299 /*mp->am_parent = 0;*/ 300 /*mp->am_ysib = 0;*/ 301 /*mp->am_osib = 0;*/ 302 /*mp->am_child = 0;*/ 303 /*mp->am_flags = 0;*/ 304 /*mp->am_error = 0;*/ 305 mp->am_gen = new_gen(); 306 /*mp->am_pref = 0;*/ 307 308 mp->am_timeo = am_timeo; 309 mp->am_attr.status = NFS_OK; 310 mp->am_fattr = gen_fattr; 311 mp->am_fattr.fsid = 42; 312 mp->am_fattr.fileid = 0; 313 mp->am_fattr.atime.seconds = clocktime(); 314 mp->am_fattr.atime.useconds = 0; 315 mp->am_fattr.mtime = mp->am_fattr.ctime = mp->am_fattr.atime; 316 317 new_ttl(mp); 318 mp->am_stats.s_mtime = mp->am_fattr.atime.seconds; 319 /*mp->am_private = 0;*/ 320 } 321 322 /* 323 * Free a mount node. 324 * The node must be already unmounted. 325 */ 326 void free_map(mp) 327 am_node *mp; 328 { 329 remove_am(mp); 330 331 if (mp->am_link) 332 free(mp->am_link); 333 if (mp->am_name) 334 free(mp->am_name); 335 if (mp->am_path) 336 free(mp->am_path); 337 if (mp->am_pref) 338 free(mp->am_pref); 339 340 if (mp->am_mnt) 341 free_mntfs(mp->am_mnt); 342 343 exported_ap_free(mp); 344 } 345 346 /* 347 * Convert from file handle to 348 * automount node. 349 */ 350 am_node *fh_to_mp3(fhp, rp, c_or_d) 351 nfs_fh *fhp; 352 int *rp; 353 int c_or_d; 354 { 355 struct am_fh *fp = (struct am_fh *) fhp; 356 am_node *ap = 0; 357 358 /* 359 * Check process id matches 360 * If it doesn't then it is probably 361 * from an old kernel cached filehandle 362 * which is now out of date. 363 */ 364 if (fp->fhh_pid != mypid) 365 goto drop; 366 367 /* 368 * Make sure the index is valid before 369 * exported_ap is referenced. 370 */ 371 if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size) 372 goto drop; 373 374 /* 375 * Get hold of the supposed mount node 376 */ 377 ap = exported_ap[fp->fhh_id]; 378 379 /* 380 * If it exists then maybe... 381 */ 382 if (ap) { 383 /* 384 * Check the generation number in the node 385 * matches the one from the kernel. If not 386 * then the old node has been timed out and 387 * a new one allocated. 388 */ 389 if (ap->am_gen != fp->fhh_gen) { 390 ap = 0; 391 goto drop; 392 } 393 394 /* 395 * If the node is hung then locate a new node 396 * for it. This implements the replicated filesystem 397 * retries. 398 */ 399 if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) { 400 int error; 401 am_node *orig_ap = ap; 402 #ifdef DEBUG 403 dlog("fh_to_mp3: %s (%s) is hung:- call lookup", 404 orig_ap->am_path, orig_ap->am_mnt->mf_info); 405 #endif /* DEBUG */ 406 /* 407 * Update modify time of parent node. 408 * With any luck the kernel will re-stat 409 * the child node and get new information. 410 */ 411 orig_ap->am_fattr.mtime.seconds = clocktime(); 412 413 /* 414 * Call the parent's lookup routine for an object 415 * with the same name. This may return -1 in error 416 * if a mount is in progress. In any case, if no 417 * mount node is returned the error code is propagated 418 * to the caller. 419 */ 420 if (c_or_d == VLOOK_CREATE) { 421 ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn)(orig_ap->am_parent, 422 orig_ap->am_name, &error, c_or_d); 423 } else { 424 ap = 0; 425 error = ESTALE; 426 } 427 if (ap == 0) { 428 if (error < 0 && amd_state == Finishing) 429 error = ENOENT; 430 *rp = error; 431 return 0; 432 } 433 /* 434 * Update last access to original node. This 435 * avoids timing it out and so sending ESTALE 436 * back to the kernel. 437 * XXX - Not sure we need this anymore (jsp, 90/10/6). 438 */ 439 new_ttl(orig_ap); 440 441 } 442 /* 443 * Disallow references to objects being unmounted, unless 444 * they are automount points. 445 */ 446 if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) && 447 !(ap->am_flags & AMF_ROOT)) { 448 if (amd_state == Finishing) 449 *rp = ENOENT; 450 else 451 *rp = -1; 452 return 0; 453 } 454 new_ttl(ap); 455 } 456 457 drop: 458 if (!ap || !ap->am_mnt) { 459 /* 460 * If we are shutting down then it is likely 461 * that this node has disappeared because of 462 * a fast timeout. To avoid things thrashing 463 * just pretend it doesn't exist at all. If 464 * ESTALE is returned, some NFS clients just 465 * keep retrying (stupid or what - if it's 466 * stale now, what's it going to be in 5 minutes?) 467 */ 468 if (amd_state == Finishing) 469 *rp = ENOENT; 470 else 471 *rp = ESTALE; 472 amd_stats.d_stale++; 473 } 474 475 return ap; 476 } 477 478 am_node *fh_to_mp(fhp) 479 nfs_fh *fhp; 480 { 481 int dummy; 482 return fh_to_mp2(fhp, &dummy); 483 } 484 485 /* 486 * Convert from automount node to 487 * file handle. 488 */ 489 void mp_to_fh(mp, fhp) 490 am_node *mp; 491 struct nfs_fh *fhp; 492 { 493 struct am_fh *fp = (struct am_fh *) fhp; 494 495 /* 496 * Take the process id 497 */ 498 fp->fhh_pid = mypid; 499 /* 500 * .. the map number 501 */ 502 fp->fhh_id = mp->am_mapno; 503 /* 504 * .. and the generation number 505 */ 506 fp->fhh_gen = mp->am_gen; 507 /* 508 * .. to make a "unique" triple that will never 509 * be reallocated except across reboots (which doesn't matter) 510 * or if we are unlucky enough to be given the same 511 * pid as a previous amd (very unlikely). 512 */ 513 } 514 515 static am_node *find_ap2 P((char *dir, am_node *mp)); 516 static am_node *find_ap2(dir, mp) 517 char *dir; 518 am_node *mp; 519 { 520 if (mp) { 521 am_node *mp2; 522 if (strcmp(mp->am_path, dir) == 0) 523 return mp; 524 525 if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && 526 strcmp(mp->am_mnt->mf_mount, dir) == 0) 527 return mp; 528 529 mp2 = find_ap2(dir, mp->am_osib); 530 if (mp2) 531 return mp2; 532 return find_ap2(dir, mp->am_child); 533 } 534 535 return 0; 536 } 537 538 /* 539 * Find the mount node corresponding 540 * to dir. dir can match either the 541 * automount path or, if the node is 542 * mounted, the mount location. 543 */ 544 am_node *find_ap P((char *dir)); 545 am_node *find_ap(dir) 546 char *dir; 547 { 548 int i; 549 550 for (i = last_used_map; i >= 0; --i) { 551 am_node *mp = exported_ap[i]; 552 if (mp && (mp->am_flags & AMF_ROOT)) { 553 mp = find_ap2(dir, exported_ap[i]); 554 if (mp) 555 return mp; 556 } 557 } 558 559 return 0; 560 } 561 562 /* 563 * Find the mount node corresponding 564 * to the mntfs structure. 565 */ 566 am_node *find_mf P((mntfs *mf)); 567 am_node *find_mf(mf) 568 mntfs *mf; 569 { 570 int i; 571 572 for (i = last_used_map; i >= 0; --i) { 573 am_node *mp = exported_ap[i]; 574 if (mp && mp->am_mnt == mf) 575 return mp; 576 } 577 return 0; 578 } 579 580 /* 581 * Get the filehandle for a particular named directory. 582 * This is used during the bootstrap to tell the kernel 583 * the filehandles of the initial automount points. 584 */ 585 nfs_fh *root_fh(dir) 586 char *dir; 587 { 588 static nfs_fh nfh; 589 am_node *mp = root_ap(dir, TRUE); 590 if (mp) { 591 mp_to_fh(mp, &nfh); 592 /* 593 * Patch up PID to match main server... 594 */ 595 if (!foreground) { 596 long pid = getppid(); 597 ((struct am_fh *) &nfh)->fhh_pid = pid; 598 #ifdef DEBUG 599 dlog("root_fh substitutes pid %d", pid); 600 #endif 601 } 602 return &nfh; 603 } 604 605 /* 606 * Should never get here... 607 */ 608 plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); 609 return 0; 610 } 611 612 am_node *root_ap(dir, path) 613 char *dir; 614 int path; 615 { 616 am_node *mp = find_ap(dir); 617 if (mp && mp->am_parent == root_node) 618 return mp; 619 620 return 0; 621 } 622 623 /* 624 * Timeout all nodes waiting on 625 * a given Fserver. 626 */ 627 void map_flush_srvr P((fserver *fs)); 628 void map_flush_srvr(fs) 629 fserver *fs; 630 { 631 int i; 632 int done = 0; 633 634 for (i = last_used_map; i >= 0; --i) { 635 am_node *mp = exported_ap[i]; 636 if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) { 637 plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host); 638 mp->am_ttl = clocktime(); 639 done = 1; 640 } 641 } 642 if (done) 643 reschedule_timeout_mp(); 644 } 645 646 /* 647 * Mount a top level automount node 648 * by calling lookup in the parent 649 * (root) node which will cause the 650 * automount node to be automounted. 651 */ 652 int mount_auto_node P((char *dir, voidp arg)); 653 int mount_auto_node(dir, arg) 654 char *dir; 655 voidp arg; 656 { 657 int error = 0; 658 (void) afs_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE); 659 if (error > 0) { 660 errno = error; /* XXX */ 661 plog(XLOG_ERROR, "Could not mount %s: %m", dir); 662 } 663 return error; 664 } 665 666 /* 667 * Cause all the top-level mount nodes 668 * to be automounted 669 */ 670 int mount_exported P((void)); 671 int mount_exported() 672 { 673 /* 674 * Iterate over all the nodes to be started 675 */ 676 return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node); 677 } 678 679 /* 680 * Construct top-level node 681 */ 682 void make_root_node P((void)); 683 void make_root_node() 684 { 685 mntfs *root_mnt; 686 char *rootmap = ROOT_MAP; 687 root_node = exported_ap_alloc(); 688 689 /* 690 * Allocate a new map 691 */ 692 init_map(root_node, ""); 693 /* 694 * Allocate a new mounted filesystem 695 */ 696 root_mnt = find_mntfs(&root_ops, (am_opts *) 0, "", rootmap, "", "", ""); 697 /* 698 * Replace the initial null reference 699 */ 700 free_mntfs(root_node->am_mnt); 701 root_node->am_mnt = root_mnt; 702 703 /* 704 * Initialise the root 705 */ 706 if (root_mnt->mf_ops->fs_init) 707 (*root_mnt->mf_ops->fs_init)(root_mnt); 708 709 /* 710 * Mount the root 711 */ 712 root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs)(root_node); 713 } 714 715 /* 716 * Cause all the nodes to be unmounted by timing 717 * them out. 718 */ 719 void umount_exported(P_void) 720 { 721 int i; 722 for (i = last_used_map; i >= 0; --i) { 723 am_node *mp = exported_ap[i]; 724 if (mp) { 725 mntfs *mf = mp->am_mnt; 726 if (mf->mf_flags & MFF_UNMOUNTING) { 727 /* 728 * If this node is being unmounted then 729 * just ignore it. However, this could 730 * prevent amd from finishing if the 731 * unmount gets blocked since the am_node 732 * will never be free'd. am_unmounted needs 733 * telling about this possibility. - XXX 734 */ 735 continue; 736 } 737 if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) { 738 /* 739 * When shutting down this had better 740 * look like a directory, otherwise it 741 * can't be unmounted! 742 */ 743 mk_fattr(mp, NFDIR); 744 } 745 if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) || 746 (mf->mf_flags & MFF_RESTART)) { 747 /* 748 * Just throw this node away without 749 * bothering to unmount it. If the 750 * server is not known to be up then 751 * don't discard the mounted on directory 752 * or Amd might hang... 753 */ 754 if (mf->mf_server && 755 (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID) 756 mf->mf_flags &= ~MFF_MKMNT; 757 am_unmounted(mp); 758 } else { 759 /* 760 * Any other node gets forcibly 761 * timed out 762 */ 763 mp->am_flags &= ~AMF_NOTIMEOUT; 764 mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; 765 mp->am_ttl = 0; 766 mp->am_timeo = 1; 767 mp->am_timeo_w = 0; 768 } 769 } 770 } 771 } 772 773 static int unmount_node P((am_node *mp)); 774 static int unmount_node(mp) 775 am_node *mp; 776 { 777 mntfs *mf = mp->am_mnt; 778 int error; 779 780 if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) { 781 /* 782 * Just unlink 783 */ 784 #ifdef DEBUG 785 if (mf->mf_flags & MFF_ERROR) 786 dlog("No-op unmount of error node %s", mf->mf_info); 787 #endif /* DEBUG */ 788 error = 0; 789 } else { 790 #ifdef DEBUG 791 dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info); 792 #endif /* DEBUG */ 793 error = (*mf->mf_ops->umount_fs)(mp); 794 } 795 796 if (error) { 797 #ifdef DEBUG 798 errno = error; /* XXX */ 799 dlog("%s: unmount: %m", mf->mf_mount); 800 #endif /* DEBUG */ 801 } 802 803 return error; 804 } 805 806 #ifdef FLUSH_KERNEL_NAME_CACHE 807 static void flush_kernel_name_cache P((am_node*)); 808 static void flush_kernel_name_cache(mp) 809 am_node *mp; 810 { 811 int islink = (mp->am_mnt->mf_fattr.type == NFLNK); 812 int isdir = (mp->am_mnt->mf_fattr.type == NFDIR); 813 int elog = 0; 814 if (islink) { 815 if (unlink(mp->am_path) < 0) 816 elog = 1; 817 } else if (isdir) { 818 if (rmdir(mp->am_path) < 0) 819 elog = 1; 820 } 821 if (elog) 822 plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path); 823 } 824 #endif /* FLUSH_KERNEL_NAME_CACHE */ 825 826 static int unmount_node_wrap P((voidp vp)); 827 static int unmount_node_wrap(vp) 828 voidp vp; 829 { 830 #ifndef FLUSH_KERNEL_NAME_CACHE 831 return unmount_node((am_node*) vp); 832 #else /* FLUSH_KERNEL_NAME_CACHE */ 833 /* 834 * This code should just say: 835 * return unmount_node((am_node *) vp); 836 * 837 * However... 838 * The kernel keeps a cached copy of filehandles, 839 * and doesn't ever uncache them (apparently). So 840 * when Amd times out a node the kernel will have a 841 * stale filehandle. When the kernel next uses the 842 * filehandle it gets ESTALE. 843 * 844 * The workaround: 845 * Arrange that when a node is removed an unlink or 846 * rmdir is done on that path so that the kernel 847 * cache is done. Yes - yuck. 848 * 849 * This can all be removed (and the background 850 * unmount flag in sfs_ops) if/when the kernel does 851 * something smarter. 852 * 853 * If the unlink or rmdir failed then just log a warning, 854 * don't fail the unmount. This can occur if the kernel 855 * client code decides that the object is still referenced 856 * and should be renamed rather than discarded. 857 * 858 * There is still a race condition here... 859 * if another process is trying to access the same 860 * filesystem at the time we get here, then 861 * it will block, since the MF_UNMOUNTING flag will 862 * be set. That may, or may not, cause the entire 863 * system to deadlock. Hmmm... 864 */ 865 am_node *mp = (am_node *) vp; 866 int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR); 867 int error = unmount_node(mp); 868 if (error) 869 return error; 870 if (isauto && (int)amd_state < (int)Finishing) 871 flush_kernel_name_cache(mp); 872 873 return 0; 874 #endif /* FLUSH_KERNEL_NAME_CACHE */ 875 } 876 877 static void free_map_if_success(rc, term, closure) 878 int rc; 879 int term; 880 voidp closure; 881 { 882 am_node *mp = (am_node *) closure; 883 mntfs *mf = mp->am_mnt; 884 885 /* 886 * Not unmounting any more 887 */ 888 mf->mf_flags &= ~MFF_UNMOUNTING; 889 890 /* 891 * If a timeout was defered because the underlying filesystem 892 * was busy then arrange for a timeout as soon as possible. 893 */ 894 if (mf->mf_flags & MFF_WANTTIMO) { 895 mf->mf_flags &= ~MFF_WANTTIMO; 896 reschedule_timeout_mp(); 897 } 898 899 if (term) { 900 plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); 901 #if defined(DEBUG) && defined(SIGTRAP) 902 /* 903 * dbx likes to put a trap on exit(). 904 * Pretend it succeeded for now... 905 */ 906 if (term == SIGTRAP) { 907 am_unmounted(mp); 908 } 909 #endif /* DEBUG */ 910 amd_stats.d_uerr++; 911 } else if (rc) { 912 if (rc == EBUSY) { 913 plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount); 914 } else { 915 errno = rc; /* XXX */ 916 plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path); 917 } 918 amd_stats.d_uerr++; 919 } else { 920 am_unmounted(mp); 921 } 922 923 /* 924 * Wakeup anything waiting for this mount 925 */ 926 wakeup((voidp) mf); 927 } 928 929 static int unmount_mp(mp) 930 am_node *mp; 931 { 932 int was_backgrounded = 0; 933 mntfs *mf = mp->am_mnt; 934 935 #ifdef notdef 936 plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); 937 #endif /* notdef */ 938 939 if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) && 940 (mf->mf_flags & MFF_MOUNTED)) { 941 if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) { 942 /* 943 * Don't try to unmount from a server that is known to be down 944 */ 945 if (!(mf->mf_flags & MFF_LOGDOWN)) { 946 /* Only log this once, otherwise gets a bit boring */ 947 plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path); 948 mf->mf_flags |= MFF_LOGDOWN; 949 } 950 } else { 951 /* Clear logdown flag - since the server must be up */ 952 mf->mf_flags &= ~MFF_LOGDOWN; 953 #ifdef DEBUG 954 dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); 955 /*dlog("Will background the unmount attempt");*/ 956 #endif /* DEBUG */ 957 /* 958 * Note that we are unmounting this node 959 */ 960 mf->mf_flags |= MFF_UNMOUNTING; 961 run_task(unmount_node_wrap, (voidp) mp, 962 free_map_if_success, (voidp) mp); 963 was_backgrounded = 1; 964 #ifdef DEBUG 965 dlog("unmount attempt backgrounded"); 966 #endif /* DEBUG */ 967 } 968 } else { 969 #ifdef DEBUG 970 dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); 971 dlog("Trying unmount in foreground"); 972 #endif 973 mf->mf_flags |= MFF_UNMOUNTING; 974 free_map_if_success(unmount_node(mp), 0, (voidp) mp); 975 #ifdef DEBUG 976 dlog("unmount attempt done"); 977 #endif /* DEBUG */ 978 } 979 980 return was_backgrounded; 981 } 982 983 void timeout_mp() 984 { 985 #define NEVER (time_t) 0 986 #define smallest_t(t1, t2) \ 987 (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) 988 #define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) 989 990 int i; 991 time_t t = NEVER; 992 time_t now = clocktime(); 993 int backoff = 0; 994 995 #ifdef DEBUG 996 dlog("Timing out automount points..."); 997 #endif /* DEBUG */ 998 for (i = last_used_map; i >= 0; --i) { 999 am_node *mp = exported_ap[i]; 1000 mntfs *mf; 1001 /* 1002 * Just continue if nothing mounted, or can't be timed out. 1003 */ 1004 if (!mp || (mp->am_flags & AMF_NOTIMEOUT)) 1005 continue; 1006 /* 1007 * Pick up mounted filesystem 1008 */ 1009 mf = mp->am_mnt; 1010 if (!mf) 1011 continue; 1012 /* 1013 * Don't delete last reference to a restarted filesystem. 1014 */ 1015 if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1) 1016 continue; 1017 /* 1018 * If there is action on this filesystem then ignore it 1019 */ 1020 if (!(mf->mf_flags & IGNORE_FLAGS)) { 1021 int expired = 0; 1022 mf->mf_flags &= ~MFF_WANTTIMO; 1023 #ifdef DEBUG 1024 /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/ 1025 #endif /* DEBUG */ 1026 if (now >= mp->am_ttl) { 1027 if (!backoff) { 1028 expired = 1; 1029 /* 1030 * Move the ttl forward to avoid thrashing effects 1031 * on the next call to timeout! 1032 */ 1033 /* sun's -tw option */ 1034 if (mp->am_timeo_w < 4 * am_timeo_w) 1035 mp->am_timeo_w += am_timeo_w; 1036 mp->am_ttl = now + mp->am_timeo_w; 1037 } else { 1038 /* 1039 * Just backoff this unmount for 1040 * a couple of seconds to avoid 1041 * many multiple unmounts being 1042 * started in parallel. 1043 */ 1044 mp->am_ttl = now + backoff + 1; 1045 } 1046 } 1047 /* 1048 * If the next ttl is smallest, use that 1049 */ 1050 t = smallest_t(t, mp->am_ttl); 1051 1052 #ifdef DEBUG 1053 /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/ 1054 #endif /* DEBUG */ 1055 1056 if (!mp->am_child && mf->mf_error >= 0 && expired) { 1057 /* 1058 * If the unmount was backgrounded then 1059 * bump the backoff counter. 1060 */ 1061 if (unmount_mp(mp)) { 1062 backoff = 2; 1063 #ifdef DEBUG 1064 /*dlog("backing off subsequent unmounts by at least %d seconds", backoff);*/ 1065 #endif 1066 } 1067 } 1068 } else if (mf->mf_flags & MFF_UNMOUNTING) { 1069 mf->mf_flags |= MFF_WANTTIMO; 1070 } 1071 } 1072 1073 if (t == NEVER) { 1074 #ifdef DEBUG 1075 dlog("No further timeouts"); 1076 #endif /* DEBUG */ 1077 t = now + ONE_HOUR; 1078 } 1079 1080 /* 1081 * Sanity check to avoid runaways. 1082 * Absolutely should never get this but 1083 * if you do without this trap amd will thrash. 1084 */ 1085 if (t <= now) { 1086 t = now + 6; /* XXX */ 1087 plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!"); 1088 } 1089 /* 1090 * XXX - when shutting down, make things happen faster 1091 */ 1092 if ((int)amd_state >= (int)Finishing) 1093 t = now + 1; 1094 #ifdef DEBUG 1095 dlog("Next mount timeout in %ds", t - now); 1096 #endif /* DEBUG */ 1097 1098 timeout_mp_id = timeout(t - now, timeout_mp, 0); 1099 1100 #undef NEVER 1101 #undef smallest_t 1102 #undef IGNORE_FLAGS 1103 } 1104 1105 /* 1106 * Cause timeout_mp to be called soonest 1107 */ 1108 void reschedule_timeout_mp() 1109 { 1110 if (timeout_mp_id) 1111 untimeout(timeout_mp_id); 1112 timeout_mp_id = timeout(0, timeout_mp, 0); 1113 } 1114