1 /* 2 * $Id: srvr_nfs.c,v 5.2.1.3 91/03/17 17:44:37 jsp Alpha $ 3 * 4 * Copyright (c) 1990 Jan-Simon Pendry 5 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Jan-Simon Pendry at Imperial College, London. 11 * 12 * %sccs.include.redist.c% 13 * 14 * @(#)srvr_nfs.c 5.2 (Berkeley) 03/17/91 15 */ 16 17 /* 18 * NFS server modeling 19 */ 20 21 #include "am.h" 22 #include <netdb.h> 23 #include <rpc/pmap_prot.h> 24 #include "mount.h" 25 26 extern qelem nfs_srvr_list; 27 qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list }; 28 29 typedef struct nfs_private { 30 u_short np_mountd; /* Mount daemon port number */ 31 char np_mountd_inval; /* Port *may* be invalid */ 32 int np_ping; /* Number of failed ping attempts */ 33 time_t np_ttl; /* Time when server is thought dead */ 34 int np_xid; /* RPC transaction id for pings */ 35 int np_error; /* Error during portmap request */ 36 } nfs_private; 37 38 static int np_xid; /* For NFS pings */ 39 #define NPXID_ALLOC() (++np_xid) 40 /*#define NPXID_ALLOC() ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/ 41 42 /* 43 * Number of pings allowed to fail before host is declared down 44 * - three-fifths of the allowed mount time... 45 #define MAX_ALLOWED_PINGS ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER) 46 */ 47 #define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1) 48 49 /* 50 * How often to ping when starting a new server 51 */ 52 #define FAST_NFS_PING 3 53 54 #if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME 55 #error: sanity check failed 56 /* 57 you cannot do things this way... 58 sufficient fast pings must be given the chance to fail 59 within the allowed mount time 60 */ 61 #endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */ 62 63 static int ping_len; 64 static char ping_buf[sizeof(struct rpc_msg) + 32]; 65 66 /* 67 * Flush any cached data 68 */ 69 void flush_srvr_nfs_cache P((void)); 70 void flush_srvr_nfs_cache() 71 { 72 fserver *fs = 0; 73 74 ITER(fs, fserver, &nfs_srvr_list) { 75 nfs_private *np = (nfs_private *) fs->fs_private; 76 if (np) { 77 np->np_mountd_inval = TRUE; 78 np->np_error = -1; 79 } 80 } 81 } 82 83 /* 84 * Startup the NFS ping 85 */ 86 static void start_ping(P_void); 87 static void start_ping() 88 { 89 XDR ping_xdr; 90 struct rpc_msg ping_msg; 91 92 rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL); 93 94 /* 95 * Create an XDR endpoint 96 */ 97 xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE); 98 99 /* 100 * Create the NFS ping message 101 */ 102 if (!xdr_callmsg(&ping_xdr, &ping_msg)) { 103 plog(XLOG_ERROR, "Couldn't create ping RPC message"); 104 going_down(3); 105 } 106 107 /* 108 * Find out how long it is 109 */ 110 ping_len = xdr_getpos(&ping_xdr); 111 112 /* 113 * Destroy the XDR endpoint - we don't need it anymore 114 */ 115 xdr_destroy(&ping_xdr); 116 } 117 118 119 /* 120 * Called when a portmap reply arrives 121 */ 122 /*ARGSUSED*/ 123 static void got_portmap P((voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done)); 124 static void got_portmap(pkt, len, sa, ia, idv, done) 125 voidp pkt; 126 int len; 127 struct sockaddr_in *sa; 128 struct sockaddr_in *ia; 129 voidp idv; 130 int done; 131 { 132 fserver *fs2 = (fserver *) idv; 133 fserver *fs = 0; 134 135 /* 136 * Find which fileserver we are talking about 137 */ 138 ITER(fs, fserver, &nfs_srvr_list) 139 if (fs == fs2) 140 break; 141 142 if (fs == fs2) { 143 u_long port = 0; /* XXX - should be short but protocol is naff */ 144 int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1; 145 nfs_private *np = (nfs_private *) fs->fs_private; 146 if (!error && port) { 147 #ifdef DEBUG 148 dlog("got port (%d) for mountd on %s", port, fs->fs_host); 149 #endif /* DEBUG */ 150 /* 151 * Grab the port number. Portmap sends back 152 * an unsigned long in native ordering, so it 153 * needs converting to a unsigned short in 154 * network ordering. 155 */ 156 np->np_mountd = htons((u_short) port); 157 np->np_mountd_inval = FALSE; 158 np->np_error = 0; 159 } else { 160 #ifdef DEBUG 161 dlog("Error fetching port for mountd on %s", fs->fs_host); 162 #endif /* DEBUG */ 163 /* 164 * Almost certainly no mountd running on remote host 165 */ 166 np->np_error = error ? error : ETIMEDOUT; 167 } 168 if (fs->fs_flags & FSF_WANT) 169 wakeup_srvr(fs); 170 } else if (done) { 171 #ifdef DEBUG 172 dlog("Got portmap for old port request"); 173 #endif /* DEBUG */ 174 } else { 175 #ifdef DEBUG 176 dlog("portmap request timed out"); 177 #endif /* DEBUG */ 178 } 179 } 180 181 /* 182 * Obtain portmap information 183 */ 184 static int call_portmap P((fserver *fs, AUTH *auth, unsigned long prog, unsigned long vers, unsigned long prot)); 185 static int call_portmap(fs, auth, prog, vers, prot) 186 fserver *fs; 187 AUTH *auth; 188 unsigned long prog, vers, prot; 189 { 190 struct rpc_msg pmap_msg; 191 int len; 192 char iobuf[UDPMSGSIZE]; 193 int error; 194 struct pmap pmap; 195 196 rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0); 197 pmap.pm_prog = prog; 198 pmap.pm_vers = vers; 199 pmap.pm_prot = prot; 200 pmap.pm_port = 0; 201 len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT, 202 &pmap_msg, (voidp) &pmap, xdr_pmap, auth); 203 if (len > 0) { 204 struct sockaddr_in sin; 205 bzero((voidp) &sin, sizeof(sin)); 206 sin = *fs->fs_ip; 207 sin.sin_port = htons(PMAPPORT); 208 error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len, 209 &sin, &sin, (voidp) fs, got_portmap); 210 } else { 211 error = -len; 212 } 213 return error; 214 } 215 216 static void nfs_keepalive P((fserver*)); 217 218 static void recompute_portmap P((fserver *fs)); 219 static void recompute_portmap(fs) 220 fserver *fs; 221 { 222 if (!nfs_auth) 223 nfs_auth = authunix_create_default(); 224 if (!nfs_auth) { 225 nfs_private *np = (nfs_private *) fs->fs_private; 226 np->np_error = ENOBUFS; 227 } else { 228 call_portmap(fs, nfs_auth, MOUNTPROG, 229 MOUNTVERS, (unsigned long) IPPROTO_UDP); 230 } 231 } 232 233 /* 234 * This is called when we get a reply to an RPC ping. 235 * The value of id was taken from the nfs_private 236 * structure when the ping was transmitted. 237 */ 238 /*ARGSUSED*/ 239 static void nfs_pinged P((voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done)); 240 static void nfs_pinged(pkt, len, sp, tsp, idv, done) 241 voidp pkt; 242 int len; 243 struct sockaddr_in *sp; 244 struct sockaddr_in *tsp; 245 voidp idv; 246 int done; 247 { 248 int xid = (int) idv; 249 fserver *fs; 250 #ifdef DEBUG 251 int found_map = 0; 252 #endif /* DEBUG */ 253 254 if (!done) 255 return; 256 257 /* 258 * For each node... 259 */ 260 ITER(fs, fserver, &nfs_srvr_list) { 261 nfs_private *np = (nfs_private *) fs->fs_private; 262 if (np->np_xid == xid) { 263 /* 264 * Reset the ping counter. 265 * Update the keepalive timer. 266 * Log what happened. 267 */ 268 if (fs->fs_flags & FSF_DOWN) { 269 fs->fs_flags &= ~FSF_DOWN; 270 if (fs->fs_flags & FSF_VALID) { 271 srvrlog(fs, "is up"); 272 } else { 273 if (np->np_ping > 1) 274 srvrlog(fs, "ok"); 275 #ifdef DEBUG 276 else 277 srvrlog(fs, "starts up"); 278 #endif 279 fs->fs_flags |= FSF_VALID; 280 } 281 282 #ifdef notdef 283 /* why ??? */ 284 if (fs->fs_flags & FSF_WANT) 285 wakeup_srvr(fs); 286 #endif /* notdef */ 287 } else { 288 if (fs->fs_flags & FSF_VALID) { 289 #ifdef DEBUG 290 dlog("file server %s type nfs is still up", fs->fs_host); 291 #endif /* DEBUG */ 292 } else { 293 if (np->np_ping > 1) 294 srvrlog(fs, "ok"); 295 fs->fs_flags |= FSF_VALID; 296 } 297 } 298 299 /* 300 * Adjust ping interval 301 */ 302 untimeout(fs->fs_cid); 303 fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs); 304 305 /* 306 * Update ttl for this server 307 */ 308 np->np_ttl = clocktime() + 309 (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1; 310 311 /* 312 * New RPC xid... 313 */ 314 np->np_xid = NPXID_ALLOC(); 315 316 /* 317 * Failed pings is zero... 318 */ 319 np->np_ping = 0; 320 321 /* 322 * Recompute portmap information if not known 323 */ 324 if (np->np_mountd_inval) 325 recompute_portmap(fs); 326 327 #ifdef DEBUG 328 found_map++; 329 #endif /* DEBUG */ 330 break; 331 } 332 } 333 334 #ifdef DEBUG 335 if (found_map == 0) 336 dlog("Spurious ping packet"); 337 #endif /* DEBUG */ 338 } 339 340 /* 341 * Called when no ping-reply received 342 */ 343 static void nfs_timed_out P((fserver *fs)); 344 static void nfs_timed_out(fs) 345 fserver *fs; 346 { 347 nfs_private *np = (nfs_private *) fs->fs_private; 348 349 /* 350 * Another ping has failed 351 */ 352 np->np_ping++; 353 354 /* 355 * Not known to be up any longer 356 */ 357 if (FSRV_ISUP(fs)) { 358 fs->fs_flags &= ~FSF_VALID; 359 if (np->np_ping > 1) 360 srvrlog(fs, "not responding"); 361 } 362 363 /* 364 * If ttl has expired then guess that it is dead 365 */ 366 if (np->np_ttl < clocktime()) { 367 if ((fs->fs_flags & FSF_DOWN) == 0) { 368 /* 369 * Server was up, but is now down. 370 */ 371 srvrlog(fs, "is down"); 372 fs->fs_flags |= FSF_DOWN|FSF_VALID; 373 /* 374 * Since the server is down, the portmap 375 * information may now be wrong, so it 376 * must be flushed from the local cache 377 */ 378 flush_nfs_fhandle_cache(fs); 379 np->np_error = -1; 380 #ifdef notdef 381 /* 382 * Pretend just one ping has failed now 383 */ 384 np->np_ping = 1; 385 #endif 386 } else { 387 /* 388 * Known to be down 389 */ 390 fs->fs_flags |= FSF_VALID; 391 #ifdef DEBUG 392 srvrlog(fs, "starts down"); 393 #endif 394 } 395 if (fs->fs_flags & FSF_WANT) 396 wakeup_srvr(fs); 397 } else { 398 #ifdef DEBUG 399 if (np->np_ping > 1) 400 dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS); 401 #endif /* DEBUG */ 402 } 403 404 /* 405 * Run keepalive again 406 */ 407 nfs_keepalive(fs); 408 } 409 410 /* 411 * Keep track of whether a server is alive 412 */ 413 static void nfs_keepalive P((fserver *fs)); 414 static void nfs_keepalive(fs) 415 fserver *fs; 416 { 417 int error; 418 nfs_private *np = (nfs_private *) fs->fs_private; 419 int fstimeo = -1; 420 421 /* 422 * Send an NFS ping to this node 423 */ 424 425 if (ping_len == 0) 426 start_ping(); 427 428 /* 429 * Queue the packet... 430 */ 431 error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf, 432 ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged); 433 434 /* 435 * See if a hard error occured 436 */ 437 switch (error) { 438 case ENETDOWN: 439 case ENETUNREACH: 440 case EHOSTDOWN: 441 case EHOSTUNREACH: 442 np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */ 443 np->np_ttl = (time_t) 0; 444 /* 445 * This causes an immediate call to nfs_timed_out 446 * whenever the server was thought to be up. 447 * See +++ below. 448 */ 449 fstimeo = 0; 450 break; 451 452 case 0: 453 #ifdef DEBUG 454 dlog("Sent NFS ping to %s", fs->fs_host); 455 #endif /* DEBUG */ 456 break; 457 } 458 459 #ifdef DEBUG 460 /*dlog("keepalive, ping = %d", np->np_ping);*/ 461 #endif /* DEBUG */ 462 463 /* 464 * Back off the ping interval if we are not getting replies and 465 * the remote system is know to be down. 466 */ 467 switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) { 468 case FSF_VALID: /* Up */ 469 if (fstimeo < 0) /* +++ see above */ 470 fstimeo = FAST_NFS_PING; 471 break; 472 473 case FSF_VALID|FSF_DOWN: /* Down */ 474 fstimeo = fs->fs_pinger; 475 break; 476 477 default: /* Unknown */ 478 fstimeo = FAST_NFS_PING; 479 break; 480 } 481 482 #ifdef DEBUG 483 dlog("NFS timeout in %d seconds", fstimeo); 484 #endif /* DEBUG */ 485 486 fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs); 487 } 488 489 int nfs_srvr_port P((fserver *fs, u_short *port, voidp wchan)); 490 int nfs_srvr_port(fs, port, wchan) 491 fserver *fs; 492 u_short *port; 493 voidp wchan; 494 { 495 int error = -1; 496 if ((fs->fs_flags & FSF_VALID) == FSF_VALID) { 497 if ((fs->fs_flags & FSF_DOWN) == 0) { 498 nfs_private *np = (nfs_private *) fs->fs_private; 499 if (np->np_error == 0) { 500 *port = np->np_mountd; 501 error = 0; 502 } else { 503 error = np->np_error; 504 } 505 /* 506 * Now go get the port mapping again in case it changed. 507 * Note that it is used even if (np_mountd_inval) 508 * is True. The flag is used simply as an 509 * indication that the mountd may be invalid, not 510 * that it is known to be invalid. 511 */ 512 if (np->np_mountd_inval) 513 recompute_portmap(fs); 514 else 515 np->np_mountd_inval = TRUE; 516 } else { 517 error = EWOULDBLOCK; 518 } 519 } 520 if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { 521 /* 522 * If a wait channel is supplied, and no 523 * error has yet occured, then arrange 524 * that a wakeup is done on the wait channel, 525 * whenever a wakeup is done on this fs node. 526 * Wakeup's are done on the fs node whenever 527 * it changes state - thus causing control to 528 * come back here and new, better things to happen. 529 */ 530 fs->fs_flags |= FSF_WANT; 531 sched_task(wakeup_task, wchan, (voidp) fs); 532 } 533 return error; 534 } 535 536 static void start_nfs_pings P((fserver *fs, int pingval)); 537 static void start_nfs_pings(fs, pingval) 538 fserver *fs; 539 int pingval; 540 { 541 if (!(fs->fs_flags & FSF_PINGING)) { 542 fs->fs_flags |= FSF_PINGING; 543 if (fs->fs_cid) 544 untimeout(fs->fs_cid); 545 if (pingval < 0) { 546 srvrlog(fs, "wired up"); 547 fs->fs_flags |= FSF_VALID; 548 fs->fs_flags &= ~FSF_DOWN; 549 } else { 550 nfs_keepalive(fs); 551 } 552 } else { 553 #ifdef DEBUG 554 dlog("Already running pings to %s", fs->fs_host); 555 #endif /* DEBUG */ 556 } 557 } 558 559 /* 560 * Find an nfs server for a host. 561 */ 562 fserver *find_nfs_srvr P((mntfs *mf)); 563 fserver *find_nfs_srvr(mf) 564 mntfs *mf; 565 { 566 fserver *fs; 567 struct hostent *hp = 0; 568 char *host = mf->mf_fo->opt_rhost; 569 struct sockaddr_in *ip; 570 nfs_private *np; 571 int pingval; 572 573 /* 574 * Get ping interval from mount options. 575 * Current only used to decide whether pings 576 * are required or not. < 0 = no pings. 577 */ 578 { struct mntent mnt; 579 mnt.mnt_opts = mf->mf_mopts; 580 pingval = hasmntval(&mnt, "ping"); 581 #ifdef HAS_TCP_NFS 582 /* 583 * Over TCP mount, don't bother to do pings. 584 * This is experimental - maybe you want to 585 * do pings anyway... 586 */ 587 if (pingval == 0 && hasmntopt(&mnt, "tcp")) 588 pingval = -1; 589 #endif /* HAS_TCP_NFS */ 590 } 591 592 593 /* 594 * lookup host address and canonical name 595 */ 596 hp = gethostbyname(host); 597 598 /* 599 * New code from Bob Harris <harris@basil-rathbone.mit.edu> 600 * Use canonical name to keep track of file server 601 * information. This way aliases do not generate 602 * multiple NFS pingers. (Except when we're normalizing 603 * hosts.) 604 */ 605 if (hp && !normalize_hosts) host = hp->h_name; 606 607 ITER(fs, fserver, &nfs_srvr_list) { 608 if (STREQ(host, fs->fs_host)) { 609 start_nfs_pings(fs, pingval); 610 fs->fs_refc++; 611 return fs; 612 } 613 } 614 615 616 617 /* 618 * Get here if we can't find an entry 619 */ 620 if (hp) { 621 switch (hp->h_addrtype) { 622 case AF_INET: 623 ip = ALLOC(sockaddr_in); 624 bzero((voidp) ip, sizeof(*ip)); 625 ip->sin_family = AF_INET; 626 bcopy((voidp) hp->h_addr, (voidp) &ip->sin_addr, sizeof(ip->sin_addr)); 627 628 ip->sin_port = htons(NFS_PORT); 629 break; 630 631 default: 632 ip = 0; 633 break; 634 } 635 } else { 636 plog(XLOG_USER, "Unknown host: %s", host); 637 ip = 0; 638 } 639 640 /* 641 * Allocate a new server 642 */ 643 fs = ALLOC(fserver); 644 fs->fs_refc = 1; 645 fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname"); 646 if (normalize_hosts) host_normalize(&fs->fs_host); 647 fs->fs_ip = ip; 648 fs->fs_cid = 0; 649 if (ip) { 650 fs->fs_flags = FSF_DOWN; /* Starts off down */ 651 } else { 652 fs->fs_flags = FSF_ERROR|FSF_VALID; 653 mf->mf_flags |= MFF_ERROR; 654 mf->mf_error = ENOENT; 655 } 656 fs->fs_type = "nfs"; 657 fs->fs_pinger = AM_PINGER; 658 np = ALLOC(nfs_private); 659 bzero((voidp) np, sizeof(*np)); 660 np->np_mountd_inval = TRUE; 661 np->np_xid = NPXID_ALLOC(); 662 np->np_error = -1; 663 /* 664 * Initially the server will be deemed dead after 665 * MAX_ALLOWED_PINGS of the fast variety have failed. 666 */ 667 np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1; 668 fs->fs_private = (voidp) np; 669 fs->fs_prfree = (void (*)()) free; 670 671 if (!(fs->fs_flags & FSF_ERROR)) { 672 /* 673 * Start of keepalive timer 674 */ 675 start_nfs_pings(fs, pingval); 676 } 677 678 /* 679 * Add to list of servers 680 */ 681 ins_que(&fs->fs_q, &nfs_srvr_list); 682 683 return fs; 684 } 685