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