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