138494Sobrien/* 2174313Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042633Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174313Sobrien * File: am-utils/amd/srvr_nfs.c 4138494Sobrien * 4238494Sobrien */ 4338494Sobrien 4438494Sobrien/* 4538494Sobrien * NFS server modeling 4638494Sobrien */ 4738494Sobrien 4838494Sobrien#ifdef HAVE_CONFIG_H 4938494Sobrien# include <config.h> 5038494Sobrien#endif /* HAVE_CONFIG_H */ 5138494Sobrien#include <am_defs.h> 5238494Sobrien#include <amd.h> 5338494Sobrien 5438494Sobrien/* 5538494Sobrien * Number of pings allowed to fail before host is declared down 5638494Sobrien * - three-fifths of the allowed mount time... 5738494Sobrien */ 5838494Sobrien#define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1) 5938494Sobrien 6038494Sobrien/* 6138494Sobrien * How often to ping when starting a new server 6238494Sobrien */ 6338494Sobrien#define FAST_NFS_PING 3 6438494Sobrien 6538494Sobrien#if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME 6638494Sobrien# error: sanity check failed in srvr_nfs.c 6738494Sobrien/* 6838494Sobrien * you cannot do things this way... 6938494Sobrien * sufficient fast pings must be given the chance to fail 7038494Sobrien * within the allowed mount time 7138494Sobrien */ 7238494Sobrien#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */ 7338494Sobrien 7438494Sobrien/* structures and typedefs */ 7538494Sobrientypedef struct nfs_private { 7638494Sobrien u_short np_mountd; /* Mount daemon port number */ 7738494Sobrien char np_mountd_inval; /* Port *may* be invalid */ 7838494Sobrien int np_ping; /* Number of failed ping attempts */ 7938494Sobrien time_t np_ttl; /* Time when server is thought dead */ 8038494Sobrien int np_xid; /* RPC transaction id for pings */ 8138494Sobrien int np_error; /* Error during portmap request */ 8238494Sobrien} nfs_private; 8338494Sobrien 8438494Sobrien/* globals */ 8538494Sobrienqelem nfs_srvr_list = {&nfs_srvr_list, &nfs_srvr_list}; 8638494Sobrien 8738494Sobrien/* statics */ 88174313Sobrienstatic int global_xid; /* For NFS pings */ 89174313Sobrien#define XID_ALLOC() (++global_xid) 9038494Sobrien 91174313Sobrien#ifdef HAVE_FS_NFS3 92174313Sobrien# define NUM_NFS_VERS 2 93174313Sobrien#else /* not HAVE_FS_NFS3 */ 94174313Sobrien# define NUM_NFS_VERS 1 95174313Sobrien#endif /* not HAVE_FS_NFS3 */ 96174313Sobrienstatic int ping_len[NUM_NFS_VERS]; 97174313Sobrienstatic char ping_buf[NUM_NFS_VERS][sizeof(struct rpc_msg) + 32]; 98174313Sobrien 9938494Sobrien#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) 10082800Sobrien/* 10182800Sobrien * Protocols we know about, in order of preference. 10282800Sobrien * 10382800Sobrien * Note that Solaris 8 and newer NetBSD systems are switching to UDP first, 10482800Sobrien * so this order may have to be adjusted for Amd in the future once more 10582800Sobrien * vendors make that change. -Erez 11/24/2000 106174313Sobrien * 107174313Sobrien * Or we might simply make this is a platform-specific order. -Ion 09/13/2003 10882800Sobrien */ 10938494Sobrienstatic char *protocols[] = { "tcp", "udp", NULL }; 11038494Sobrien#endif /* defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ 11138494Sobrien 11238494Sobrien/* forward definitions */ 11338494Sobrienstatic void nfs_keepalive(voidp); 11438494Sobrien 11538494Sobrien 11638494Sobrien/* 117174313Sobrien * Flush cached data for an fserver (or for all, if fs==NULL) 11838494Sobrien */ 11938494Sobrienvoid 120174313Sobrienflush_srvr_nfs_cache(fserver *fs) 12138494Sobrien{ 122174313Sobrien fserver *fs2 = NULL; 12338494Sobrien 124174313Sobrien ITER(fs2, fserver, &nfs_srvr_list) { 125174313Sobrien if (fs == NULL || fs == fs2) { 126174313Sobrien nfs_private *np = (nfs_private *) fs2->fs_private; 127174313Sobrien if (np) { 128174313Sobrien np->np_mountd_inval = TRUE; 129174313Sobrien np->np_error = -1; 130174313Sobrien } 13138494Sobrien } 13238494Sobrien } 13338494Sobrien} 13438494Sobrien 13538494Sobrien 13638494Sobrien/* 13738494Sobrien * Startup the NFS ping for a particular version. 13838494Sobrien */ 13938494Sobrienstatic void 140174313Sobriencreate_ping_payload(u_long nfs_version) 14138494Sobrien{ 14238494Sobrien XDR ping_xdr; 14338494Sobrien struct rpc_msg ping_msg; 14438494Sobrien 14538494Sobrien /* 14638494Sobrien * Non nfs mounts like /afs/glue.umd.edu have ended up here. 14738494Sobrien */ 14838494Sobrien if (nfs_version == 0) { 14938494Sobrien nfs_version = NFS_VERSION; 150174313Sobrien plog(XLOG_WARNING, "create_ping_payload: nfs_version = 0, changed to 2"); 151174313Sobrien } else 152174313Sobrien plog(XLOG_INFO, "create_ping_payload: nfs_version: %d", (int) nfs_version); 15338494Sobrien 15438494Sobrien rpc_msg_init(&ping_msg, NFS_PROGRAM, nfs_version, NFSPROC_NULL); 15538494Sobrien 15638494Sobrien /* 15738494Sobrien * Create an XDR endpoint 15838494Sobrien */ 159174313Sobrien xdrmem_create(&ping_xdr, ping_buf[nfs_version - NFS_VERSION], sizeof(ping_buf[0]), XDR_ENCODE); 16038494Sobrien 16138494Sobrien /* 16238494Sobrien * Create the NFS ping message 16338494Sobrien */ 16438494Sobrien if (!xdr_callmsg(&ping_xdr, &ping_msg)) { 16538494Sobrien plog(XLOG_ERROR, "Couldn't create ping RPC message"); 16638494Sobrien going_down(3); 16738494Sobrien } 16838494Sobrien /* 16938494Sobrien * Find out how long it is 17038494Sobrien */ 171174313Sobrien ping_len[nfs_version - NFS_VERSION] = xdr_getpos(&ping_xdr); 17238494Sobrien 17338494Sobrien /* 17438494Sobrien * Destroy the XDR endpoint - we don't need it anymore 17538494Sobrien */ 17638494Sobrien xdr_destroy(&ping_xdr); 17738494Sobrien} 17838494Sobrien 17938494Sobrien 18038494Sobrien/* 18138494Sobrien * Called when a portmap reply arrives 18238494Sobrien */ 18338494Sobrienstatic void 18482800Sobriengot_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done) 18538494Sobrien{ 18638494Sobrien fserver *fs2 = (fserver *) idv; 18738494Sobrien fserver *fs = 0; 18838494Sobrien 18938494Sobrien /* 19038494Sobrien * Find which fileserver we are talking about 19138494Sobrien */ 19238494Sobrien ITER(fs, fserver, &nfs_srvr_list) 193174313Sobrien if (fs == fs2) 19438494Sobrien break; 19538494Sobrien 19638494Sobrien if (fs == fs2) { 19738494Sobrien u_long port = 0; /* XXX - should be short but protocol is naff */ 19838494Sobrien int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, (XDRPROC_T_TYPE) xdr_u_long) : -1; 19938494Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 20038494Sobrien 20138494Sobrien if (!error && port) { 20251300Sobrien dlog("got port (%d) for mountd on %s", (int) port, fs->fs_host); 20338494Sobrien /* 20438494Sobrien * Grab the port number. Portmap sends back 20538494Sobrien * an u_long in native ordering, so it 20638494Sobrien * needs converting to a u_short in 20738494Sobrien * network ordering. 20838494Sobrien */ 20938494Sobrien np->np_mountd = htons((u_short) port); 21038494Sobrien np->np_mountd_inval = FALSE; 21138494Sobrien np->np_error = 0; 21238494Sobrien } else { 21338494Sobrien dlog("Error fetching port for mountd on %s", fs->fs_host); 21451300Sobrien dlog("\t error=%d, port=%d", error, (int) port); 21538494Sobrien /* 21638494Sobrien * Almost certainly no mountd running on remote host 21738494Sobrien */ 21838494Sobrien np->np_error = error ? error : ETIMEDOUT; 21938494Sobrien } 22038494Sobrien 22138494Sobrien if (fs->fs_flags & FSF_WANT) 22238494Sobrien wakeup_srvr(fs); 22338494Sobrien } else if (done) { 22438494Sobrien dlog("Got portmap for old port request"); 22538494Sobrien } else { 22638494Sobrien dlog("portmap request timed out"); 22738494Sobrien } 22838494Sobrien} 22938494Sobrien 23038494Sobrien 23138494Sobrien/* 23238494Sobrien * Obtain portmap information 23338494Sobrien */ 23438494Sobrienstatic int 23582800Sobriencall_portmap(fserver *fs, AUTH *auth, u_long prog, u_long vers, u_long prot) 23638494Sobrien{ 23738494Sobrien struct rpc_msg pmap_msg; 23838494Sobrien int len; 23938494Sobrien char iobuf[UDPMSGSIZE]; 24038494Sobrien int error; 24138494Sobrien struct pmap pmap; 24238494Sobrien 24338494Sobrien rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, PMAPPROC_NULL); 24438494Sobrien pmap.pm_prog = prog; 24538494Sobrien pmap.pm_vers = vers; 24638494Sobrien pmap.pm_prot = prot; 24738494Sobrien pmap.pm_port = 0; 24838494Sobrien len = make_rpc_packet(iobuf, 24938494Sobrien sizeof(iobuf), 25038494Sobrien PMAPPROC_GETPORT, 25138494Sobrien &pmap_msg, 25238494Sobrien (voidp) &pmap, 25338494Sobrien (XDRPROC_T_TYPE) xdr_pmap, 25438494Sobrien auth); 25538494Sobrien if (len > 0) { 25638494Sobrien struct sockaddr_in sin; 25738494Sobrien memset((voidp) &sin, 0, sizeof(sin)); 25838494Sobrien sin = *fs->fs_ip; 25938494Sobrien sin.sin_port = htons(PMAPPORT); 260174313Sobrien error = fwd_packet(RPC_XID_PORTMAP, iobuf, len, 26138494Sobrien &sin, &sin, (voidp) fs, got_portmap); 26238494Sobrien } else { 26338494Sobrien error = -len; 26438494Sobrien } 26538494Sobrien 26638494Sobrien return error; 26738494Sobrien} 26838494Sobrien 26938494Sobrien 27038494Sobrienstatic void 27138494Sobrienrecompute_portmap(fserver *fs) 27238494Sobrien{ 27338494Sobrien int error; 27438494Sobrien u_long mnt_version; 27538494Sobrien 276174313Sobrien /* 277174313Sobrien * No portmap calls for pure WebNFS servers. 278174313Sobrien */ 279174313Sobrien if (fs->fs_flags & FSF_WEBNFS) 280174313Sobrien return; 281174313Sobrien 28238494Sobrien if (nfs_auth) 28338494Sobrien error = 0; 28438494Sobrien else 28538494Sobrien error = make_nfs_auth(); 28638494Sobrien 28738494Sobrien if (error) { 28838494Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 28938494Sobrien np->np_error = error; 29038494Sobrien return; 29138494Sobrien } 29238494Sobrien 29338494Sobrien if (fs->fs_version == 0) 29438494Sobrien plog(XLOG_WARNING, "recompute_portmap: nfs_version = 0 fixed"); 29538494Sobrien 296174313Sobrien plog(XLOG_INFO, "recompute_portmap: NFS version %d on %s", 297174313Sobrien (int) fs->fs_version, fs->fs_host); 29838494Sobrien#ifdef HAVE_FS_NFS3 29938494Sobrien if (fs->fs_version == NFS_VERSION3) 300174313Sobrien mnt_version = AM_MOUNTVERS3; 30138494Sobrien else 30238494Sobrien#endif /* HAVE_FS_NFS3 */ 30338494Sobrien mnt_version = MOUNTVERS; 30438494Sobrien 30551300Sobrien plog(XLOG_INFO, "Using MOUNT version: %d", (int) mnt_version); 30638494Sobrien call_portmap(fs, nfs_auth, MOUNTPROG, mnt_version, (u_long) IPPROTO_UDP); 30738494Sobrien} 30838494Sobrien 30938494Sobrien 310174313Sobrienint 311174313Sobrienget_mountd_port(fserver *fs, u_short *port, wchan_t wchan) 312174313Sobrien{ 313174313Sobrien int error = -1; 314174313Sobrien if (FSRV_ISDOWN(fs)) 315174313Sobrien return EWOULDBLOCK; 316174313Sobrien 317174313Sobrien if (FSRV_ISUP(fs)) { 318174313Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 319174313Sobrien if (np->np_error == 0) { 320174313Sobrien *port = np->np_mountd; 321174313Sobrien error = 0; 322174313Sobrien } else { 323174313Sobrien error = np->np_error; 324174313Sobrien } 325174313Sobrien /* 326174313Sobrien * Now go get the port mapping again in case it changed. 327174313Sobrien * Note that it is used even if (np_mountd_inval) 328174313Sobrien * is True. The flag is used simply as an 329174313Sobrien * indication that the mountd may be invalid, not 330174313Sobrien * that it is known to be invalid. 331174313Sobrien */ 332174313Sobrien if (np->np_mountd_inval) 333174313Sobrien recompute_portmap(fs); 334174313Sobrien else 335174313Sobrien np->np_mountd_inval = TRUE; 336174313Sobrien } 337174313Sobrien if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { 338174313Sobrien /* 339174313Sobrien * If a wait channel is supplied, and no 340174313Sobrien * error has yet occurred, then arrange 341174313Sobrien * that a wakeup is done on the wait channel, 342174313Sobrien * whenever a wakeup is done on this fs node. 343174313Sobrien * Wakeup's are done on the fs node whenever 344174313Sobrien * it changes state - thus causing control to 345174313Sobrien * come back here and new, better things to happen. 346174313Sobrien */ 347174313Sobrien fs->fs_flags |= FSF_WANT; 348174313Sobrien sched_task(wakeup_task, wchan, (wchan_t) fs); 349174313Sobrien } 350174313Sobrien return error; 351174313Sobrien} 352174313Sobrien 353174313Sobrien 35438494Sobrien/* 35538494Sobrien * This is called when we get a reply to an RPC ping. 35638494Sobrien * The value of id was taken from the nfs_private 35738494Sobrien * structure when the ping was transmitted. 35838494Sobrien */ 35938494Sobrienstatic void 360174313Sobriennfs_keepalive_callback(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done) 36138494Sobrien{ 362174313Sobrien int xid = (long) idv; /* cast needed for 64-bit archs */ 36338494Sobrien fserver *fs; 36438494Sobrien int found_map = 0; 36538494Sobrien 36638494Sobrien if (!done) 36738494Sobrien return; 36838494Sobrien 36938494Sobrien /* 37038494Sobrien * For each node... 37138494Sobrien */ 37238494Sobrien ITER(fs, fserver, &nfs_srvr_list) { 37338494Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 37438494Sobrien if (np->np_xid == xid && (fs->fs_flags & FSF_PINGING)) { 37538494Sobrien /* 37638494Sobrien * Reset the ping counter. 37738494Sobrien * Update the keepalive timer. 37838494Sobrien * Log what happened. 37938494Sobrien */ 38038494Sobrien if (fs->fs_flags & FSF_DOWN) { 38138494Sobrien fs->fs_flags &= ~FSF_DOWN; 38238494Sobrien if (fs->fs_flags & FSF_VALID) { 38338494Sobrien srvrlog(fs, "is up"); 38438494Sobrien } else { 38538494Sobrien if (np->np_ping > 1) 38638494Sobrien srvrlog(fs, "ok"); 38738494Sobrien else 38838494Sobrien srvrlog(fs, "starts up"); 38938494Sobrien fs->fs_flags |= FSF_VALID; 39038494Sobrien } 39138494Sobrien 39238494Sobrien map_flush_srvr(fs); 39338494Sobrien } else { 39438494Sobrien if (fs->fs_flags & FSF_VALID) { 39538494Sobrien dlog("file server %s type nfs is still up", fs->fs_host); 39638494Sobrien } else { 39738494Sobrien if (np->np_ping > 1) 39838494Sobrien srvrlog(fs, "ok"); 39938494Sobrien fs->fs_flags |= FSF_VALID; 40038494Sobrien } 40138494Sobrien } 40238494Sobrien 40338494Sobrien /* 40438494Sobrien * Adjust ping interval 40538494Sobrien */ 40638494Sobrien untimeout(fs->fs_cid); 40738494Sobrien fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs); 40838494Sobrien 40938494Sobrien /* 41038494Sobrien * Update ttl for this server 41138494Sobrien */ 412174313Sobrien np->np_ttl = clocktime(NULL) + 41338494Sobrien (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1; 41438494Sobrien 41538494Sobrien /* 41638494Sobrien * New RPC xid... 41738494Sobrien */ 418174313Sobrien np->np_xid = XID_ALLOC(); 41938494Sobrien 42038494Sobrien /* 42138494Sobrien * Failed pings is zero... 42238494Sobrien */ 42338494Sobrien np->np_ping = 0; 42438494Sobrien 42538494Sobrien /* 42638494Sobrien * Recompute portmap information if not known 42738494Sobrien */ 42838494Sobrien if (np->np_mountd_inval) 42938494Sobrien recompute_portmap(fs); 43038494Sobrien 43138494Sobrien found_map++; 43238494Sobrien break; 43338494Sobrien } 43438494Sobrien } 43538494Sobrien 43638494Sobrien if (found_map == 0) 43738494Sobrien dlog("Spurious ping packet"); 43838494Sobrien} 43938494Sobrien 44038494Sobrien 441174313Sobrienstatic void 442174313Sobriencheck_fs_addr_change(fserver *fs) 443174313Sobrien{ 444174313Sobrien struct hostent *hp = NULL; 445174313Sobrien struct in_addr ia; 446174313Sobrien char *old_ipaddr, *new_ipaddr; 447174313Sobrien 448174313Sobrien hp = gethostbyname(fs->fs_host); 449174313Sobrien if (!hp || 450174313Sobrien hp->h_addrtype != AF_INET || 451174313Sobrien !STREQ((char *) hp->h_name, fs->fs_host) || 452174313Sobrien memcmp((voidp) &fs->fs_ip->sin_addr, 453174313Sobrien (voidp) hp->h_addr, 454174313Sobrien sizeof(fs->fs_ip->sin_addr)) == 0) 455174313Sobrien return; 456174313Sobrien /* if got here: downed server changed IP address */ 457174313Sobrien old_ipaddr = strdup(inet_ntoa(fs->fs_ip->sin_addr)); 458174313Sobrien memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr)); 459174313Sobrien new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */ 460174313Sobrien plog(XLOG_WARNING, "EZK: down fileserver %s changed ip: %s -> %s", 461174313Sobrien fs->fs_host, old_ipaddr, new_ipaddr); 462174313Sobrien XFREE(old_ipaddr); 463174313Sobrien /* copy new IP addr */ 464174313Sobrien memmove((voidp) &fs->fs_ip->sin_addr, 465174313Sobrien (voidp) hp->h_addr, 466174313Sobrien sizeof(fs->fs_ip->sin_addr)); 467174313Sobrien /* XXX: do we need to un/set these flags? */ 468174313Sobrien fs->fs_flags &= ~FSF_DOWN; 469174313Sobrien fs->fs_flags |= FSF_VALID | FSF_WANT; 470174313Sobrien map_flush_srvr(fs); /* XXX: a race with flush_srvr_nfs_cache? */ 471174313Sobrien flush_srvr_nfs_cache(fs); 472174313Sobrien fs->fs_flags |= FSF_FORCE_UNMOUNT; 473174313Sobrien 474174313Sobrien#if 0 475174313Sobrien flush_nfs_fhandle_cache(fs); /* done in caller: nfs_keepalive_timeout */ 476174313Sobrien /* XXX: need to purge nfs_private so that somehow it will get re-initialized? */ 477174313Sobrien#endif 478174313Sobrien} 479174313Sobrien 480174313Sobrien 48138494Sobrien/* 48238494Sobrien * Called when no ping-reply received 48338494Sobrien */ 48438494Sobrienstatic void 485174313Sobriennfs_keepalive_timeout(voidp v) 48638494Sobrien{ 48738494Sobrien fserver *fs = v; 48838494Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 48938494Sobrien 49038494Sobrien /* 49138494Sobrien * Another ping has failed 49238494Sobrien */ 49338494Sobrien np->np_ping++; 494119682Smbr if (np->np_ping > 1) 495119682Smbr srvrlog(fs, "not responding"); 49638494Sobrien 49738494Sobrien /* 49838494Sobrien * Not known to be up any longer 49938494Sobrien */ 500119682Smbr if (FSRV_ISUP(fs)) 50138494Sobrien fs->fs_flags &= ~FSF_VALID; 50238494Sobrien 50338494Sobrien /* 50438494Sobrien * If ttl has expired then guess that it is dead 50538494Sobrien */ 506174313Sobrien if (np->np_ttl < clocktime(NULL)) { 50738494Sobrien int oflags = fs->fs_flags; 508119682Smbr dlog("ttl has expired"); 50938494Sobrien if ((fs->fs_flags & FSF_DOWN) == 0) { 51038494Sobrien /* 51138494Sobrien * Server was up, but is now down. 51238494Sobrien */ 51338494Sobrien srvrlog(fs, "is down"); 51438494Sobrien fs->fs_flags |= FSF_DOWN | FSF_VALID; 51538494Sobrien /* 51638494Sobrien * Since the server is down, the portmap 51738494Sobrien * information may now be wrong, so it 51838494Sobrien * must be flushed from the local cache 51938494Sobrien */ 52038494Sobrien flush_nfs_fhandle_cache(fs); 52138494Sobrien np->np_error = -1; 522174313Sobrien check_fs_addr_change(fs); /* check if IP addr of fserver changed */ 52338494Sobrien } else { 52438494Sobrien /* 52538494Sobrien * Known to be down 52638494Sobrien */ 52738494Sobrien if ((fs->fs_flags & FSF_VALID) == 0) 52838494Sobrien srvrlog(fs, "starts down"); 52938494Sobrien fs->fs_flags |= FSF_VALID; 53038494Sobrien } 53138494Sobrien if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT)) 53238494Sobrien wakeup_srvr(fs); 533119682Smbr /* 534119682Smbr * Reset failed ping count 535119682Smbr */ 536119682Smbr np->np_ping = 0; 53738494Sobrien } else { 53838494Sobrien if (np->np_ping > 1) 53938494Sobrien dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS); 54038494Sobrien } 54138494Sobrien 54238494Sobrien /* 543119682Smbr * New RPC xid, so any late responses to the previous ping 544119682Smbr * get ignored... 545119682Smbr */ 546174313Sobrien np->np_xid = XID_ALLOC(); 547119682Smbr 548119682Smbr /* 54938494Sobrien * Run keepalive again 55038494Sobrien */ 55138494Sobrien nfs_keepalive(fs); 55238494Sobrien} 55338494Sobrien 55438494Sobrien 55538494Sobrien/* 55638494Sobrien * Keep track of whether a server is alive 55738494Sobrien */ 55838494Sobrienstatic void 55938494Sobriennfs_keepalive(voidp v) 56038494Sobrien{ 56138494Sobrien fserver *fs = v; 56238494Sobrien int error; 56338494Sobrien nfs_private *np = (nfs_private *) fs->fs_private; 56438494Sobrien int fstimeo = -1; 56538494Sobrien 56638494Sobrien /* 56738494Sobrien * Send an NFS ping to this node 56838494Sobrien */ 56938494Sobrien 570174313Sobrien if (ping_len[fs->fs_version - NFS_VERSION] == 0) 571174313Sobrien create_ping_payload(fs->fs_version); 57238494Sobrien 57338494Sobrien /* 57438494Sobrien * Queue the packet... 57538494Sobrien */ 57638494Sobrien error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), 577174313Sobrien ping_buf[fs->fs_version - NFS_VERSION], 578174313Sobrien ping_len[fs->fs_version - NFS_VERSION], 57938494Sobrien fs->fs_ip, 58038494Sobrien (struct sockaddr_in *) 0, 581174313Sobrien (voidp) ((long) np->np_xid), /* cast needed for 64-bit archs */ 582174313Sobrien nfs_keepalive_callback); 58338494Sobrien 58438494Sobrien /* 58542633Sobrien * See if a hard error occurred 58638494Sobrien */ 58738494Sobrien switch (error) { 58838494Sobrien case ENETDOWN: 58938494Sobrien case ENETUNREACH: 59038494Sobrien case EHOSTDOWN: 59138494Sobrien case EHOSTUNREACH: 59238494Sobrien np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */ 59338494Sobrien np->np_ttl = (time_t) 0; 59438494Sobrien /* 595174313Sobrien * This causes an immediate call to nfs_keepalive_timeout 59638494Sobrien * whenever the server was thought to be up. 59738494Sobrien * See +++ below. 59838494Sobrien */ 59938494Sobrien fstimeo = 0; 60038494Sobrien break; 60138494Sobrien 60238494Sobrien case 0: 60338494Sobrien dlog("Sent NFS ping to %s", fs->fs_host); 60438494Sobrien break; 60538494Sobrien } 60638494Sobrien 60738494Sobrien /* 60838494Sobrien * Back off the ping interval if we are not getting replies and 609174313Sobrien * the remote system is known to be down. 61038494Sobrien */ 61138494Sobrien switch (fs->fs_flags & (FSF_DOWN | FSF_VALID)) { 61238494Sobrien case FSF_VALID: /* Up */ 61338494Sobrien if (fstimeo < 0) /* +++ see above */ 61438494Sobrien fstimeo = FAST_NFS_PING; 61538494Sobrien break; 61638494Sobrien 61738494Sobrien case FSF_VALID | FSF_DOWN: /* Down */ 61838494Sobrien fstimeo = fs->fs_pinger; 61938494Sobrien break; 62038494Sobrien 62138494Sobrien default: /* Unknown */ 62238494Sobrien fstimeo = FAST_NFS_PING; 62338494Sobrien break; 62438494Sobrien } 62538494Sobrien 62638494Sobrien dlog("NFS timeout in %d seconds", fstimeo); 62738494Sobrien 628174313Sobrien fs->fs_cid = timeout(fstimeo, nfs_keepalive_timeout, (voidp) fs); 62938494Sobrien} 63038494Sobrien 63138494Sobrien 632174313Sobrienstatic void 633174313Sobrienstart_nfs_pings(fserver *fs, int pingval) 63438494Sobrien{ 635174313Sobrien if (pingval == 0) /* could be because ping mnt option not found */ 636174313Sobrien pingval = AM_PINGER; 637174313Sobrien /* if pings haven't been initalized, then init them for first time */ 638174313Sobrien if (fs->fs_flags & FSF_PING_UNINIT) { 639174313Sobrien fs->fs_flags &= ~FSF_PING_UNINIT; 640174313Sobrien plog(XLOG_INFO, "initializing %s's pinger to %d sec", fs->fs_host, pingval); 641174313Sobrien goto do_pings; 64238494Sobrien } 64338494Sobrien 644174313Sobrien if ((fs->fs_flags & FSF_PINGING) && fs->fs_pinger == pingval) { 645174313Sobrien dlog("already running pings to %s", fs->fs_host); 646119682Smbr return; 64738494Sobrien } 648119682Smbr 649174313Sobrien /* if got here, then we need to update the ping value */ 650174313Sobrien plog(XLOG_INFO, "changing %s's ping value from %d%s to %d%s", 651174313Sobrien fs->fs_host, 652174313Sobrien fs->fs_pinger, (fs->fs_pinger < 0 ? " (off)" : ""), 653174313Sobrien pingval, (pingval < 0 ? " (off)" : "")); 654174313Sobrien do_pings: 655174313Sobrien fs->fs_pinger = pingval; 656174313Sobrien 657119682Smbr if (fs->fs_cid) 658119682Smbr untimeout(fs->fs_cid); 659119682Smbr if (pingval < 0) { 660174313Sobrien srvrlog(fs, "wired up (pings disabled)"); 661119682Smbr fs->fs_flags |= FSF_VALID; 662119682Smbr fs->fs_flags &= ~FSF_DOWN; 663119682Smbr } else { 664119682Smbr fs->fs_flags |= FSF_PINGING; 665119682Smbr nfs_keepalive(fs); 666119682Smbr } 66738494Sobrien} 66838494Sobrien 66938494Sobrien 67038494Sobrien/* 67138494Sobrien * Find an nfs server for a host. 67238494Sobrien */ 67338494Sobrienfserver * 67438494Sobrienfind_nfs_srvr(mntfs *mf) 67538494Sobrien{ 67638494Sobrien char *host = mf->mf_fo->opt_rhost; 67738494Sobrien fserver *fs; 67838494Sobrien int pingval; 67938494Sobrien mntent_t mnt; 68038494Sobrien nfs_private *np; 681174313Sobrien struct hostent *hp = NULL; 682174313Sobrien struct sockaddr_in *ip = NULL; 68338494Sobrien u_long nfs_version = 0; /* default is no version specified */ 684174313Sobrien u_long best_nfs_version = 0; 685174313Sobrien char *nfs_proto = NULL; /* no IP protocol either */ 686174313Sobrien int nfs_port = 0; 687174313Sobrien int nfs_port_opt = 0; 688174313Sobrien int fserver_is_down = 0; 68938494Sobrien 69038494Sobrien /* 69138494Sobrien * Get ping interval from mount options. 69238494Sobrien * Current only used to decide whether pings 69338494Sobrien * are required or not. < 0 = no pings. 69438494Sobrien */ 69538494Sobrien mnt.mnt_opts = mf->mf_mopts; 69638494Sobrien pingval = hasmntval(&mnt, "ping"); 69738494Sobrien 698174313Sobrien if (mf->mf_flags & MFF_NFS_SCALEDOWN) { 699174313Sobrien /* 700174313Sobrien * the server granted us a filehandle, but we were unable to mount it. 701174313Sobrien * therefore, scale down to NFSv2/UDP and try again. 702174313Sobrien */ 703174313Sobrien nfs_version = NFS_VERSION; 704174313Sobrien nfs_proto = "udp"; 705174313Sobrien plog(XLOG_WARNING, "find_nfs_srvr: NFS mount failed, trying again with NFSv2/UDP"); 706174313Sobrien mf->mf_flags &= ~MFF_NFS_SCALEDOWN; 707174313Sobrien } else { 708174313Sobrien /* 709174313Sobrien * Get the NFS version from the mount options. This is used 710174313Sobrien * to decide the highest NFS version to try. 711174313Sobrien */ 71238494Sobrien#ifdef MNTTAB_OPT_VERS 713174313Sobrien nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS); 71438494Sobrien#endif /* MNTTAB_OPT_VERS */ 71538494Sobrien 71638494Sobrien#ifdef MNTTAB_OPT_PROTO 717174313Sobrien { 718174313Sobrien char *proto_opt = hasmnteq(&mnt, MNTTAB_OPT_PROTO); 719174313Sobrien if (proto_opt) { 720174313Sobrien char **p; 721174313Sobrien for (p = protocols; *p; p++) 722174313Sobrien if (NSTREQ(proto_opt, *p, strlen(*p))) { 723174313Sobrien nfs_proto = *p; 724174313Sobrien break; 725174313Sobrien } 726174313Sobrien if (*p == NULL) 727174313Sobrien plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s", 728174313Sobrien host, mf->mf_fo->opt_rfs); 729174313Sobrien } 73038494Sobrien } 73138494Sobrien#endif /* MNTTAB_OPT_PROTO */ 73238494Sobrien 73342633Sobrien#ifdef HAVE_NFS_NFSV2_H 734174313Sobrien /* allow overriding if nfsv2 option is specified in mount options */ 735174313Sobrien if (amu_hasmntopt(&mnt, "nfsv2")) { 736174313Sobrien nfs_version = NFS_VERSION;/* nullify any ``vers=X'' statements */ 737174313Sobrien nfs_proto = "udp"; /* nullify any ``proto=tcp'' statements */ 738174313Sobrien plog(XLOG_WARNING, "found compatibility option \"nfsv2\": set options vers=2,proto=udp for host %s", host); 739174313Sobrien } 74042633Sobrien#endif /* HAVE_NFS_NFSV2_H */ 74139159Sobrien 742174313Sobrien /* check if we've globally overridden the NFS version/protocol */ 743174313Sobrien if (gopt.nfs_vers) { 744174313Sobrien nfs_version = gopt.nfs_vers; 745174313Sobrien plog(XLOG_INFO, "find_nfs_srvr: force NFS version to %d", 746174313Sobrien (int) nfs_version); 747174313Sobrien } 748174313Sobrien if (gopt.nfs_proto) { 749174313Sobrien nfs_proto = gopt.nfs_proto; 750174313Sobrien plog(XLOG_INFO, "find_nfs_srvr: force NFS protocol transport to %s", nfs_proto); 751174313Sobrien } 75282800Sobrien } 75382800Sobrien 75438494Sobrien /* 75538494Sobrien * lookup host address and canonical name 75638494Sobrien */ 75738494Sobrien hp = gethostbyname(host); 75838494Sobrien 75938494Sobrien /* 76038494Sobrien * New code from Bob Harris <harris@basil-rathbone.mit.edu> 76138494Sobrien * Use canonical name to keep track of file server 76238494Sobrien * information. This way aliases do not generate 76338494Sobrien * multiple NFS pingers. (Except when we're normalizing 76438494Sobrien * hosts.) 76538494Sobrien */ 76638494Sobrien if (hp && !(gopt.flags & CFM_NORMALIZE_HOSTNAMES)) 76738494Sobrien host = (char *) hp->h_name; 76838494Sobrien 76938494Sobrien if (hp) { 77038494Sobrien switch (hp->h_addrtype) { 77138494Sobrien case AF_INET: 77238494Sobrien ip = ALLOC(struct sockaddr_in); 77338494Sobrien memset((voidp) ip, 0, sizeof(*ip)); 774174313Sobrien /* as per POSIX, sin_len need not be set (used internally by kernel) */ 77538494Sobrien ip->sin_family = AF_INET; 77638494Sobrien memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr)); 77738494Sobrien break; 77838494Sobrien 77938494Sobrien default: 780174313Sobrien plog(XLOG_USER, "No IP address for host %s", host); 781174313Sobrien goto no_dns; 78238494Sobrien } 78338494Sobrien } else { 78438494Sobrien plog(XLOG_USER, "Unknown host: %s", host); 785174313Sobrien goto no_dns; 78638494Sobrien } 78738494Sobrien 78838494Sobrien /* 789174313Sobrien * This may not be the best way to do things, but it really doesn't make 790174313Sobrien * sense to query a file server which is marked as 'down' for any 791174313Sobrien * version/proto combination. 79238494Sobrien */ 793174313Sobrien ITER(fs, fserver, &nfs_srvr_list) { 794174313Sobrien if (FSRV_ISDOWN(fs) && 795174313Sobrien STREQ(host, fs->fs_host)) { 796174313Sobrien plog(XLOG_WARNING, "fileserver %s is already hung - not running NFS proto/version discovery", host); 797174313Sobrien fs->fs_refc++; 798174313Sobrien if (ip) 799174313Sobrien XFREE(ip); 800174313Sobrien return fs; 801174313Sobrien } 802174313Sobrien } 803174313Sobrien 804174313Sobrien /* 805174313Sobrien * Get the NFS Version, and verify server is up. 806174313Sobrien * If the client only supports NFSv2, hardcode it but still try to 807174313Sobrien * contact the remote portmapper to see if the service is running. 808174313Sobrien */ 809174313Sobrien#ifndef HAVE_FS_NFS3 810174313Sobrien nfs_version = NFS_VERSION; 811174313Sobrien nfs_proto = "udp"; 812174313Sobrien plog(XLOG_INFO, "The client supports only NFS(2,udp)"); 813174313Sobrien#endif /* not HAVE_FS_NFS3 */ 814174313Sobrien 815174313Sobrien 816174313Sobrien if (amu_hasmntopt(&mnt, MNTTAB_OPT_PUBLIC)) { 817174313Sobrien /* 818174313Sobrien * Use WebNFS to obtain file handles. 819174313Sobrien */ 820174313Sobrien mf->mf_flags |= MFF_WEBNFS; 821174313Sobrien plog(XLOG_INFO, "%s option used, NOT contacting the portmapper on %s", 822174313Sobrien MNTTAB_OPT_PUBLIC, host); 823174313Sobrien /* 824174313Sobrien * Prefer NFSv3/tcp if the client supports it (cf. RFC 2054, 7). 825174313Sobrien */ 826174313Sobrien if (!nfs_version) { 82738494Sobrien#ifdef HAVE_FS_NFS3 828174313Sobrien nfs_version = NFS_VERSION3; 829174313Sobrien#else /* not HAVE_FS_NFS3 */ 830174313Sobrien nfs_version = NFS_VERSION; 831174313Sobrien#endif /* not HAVE_FS_NFS3 */ 832174313Sobrien plog(XLOG_INFO, "No NFS version specified, will use NFSv%d", 833174313Sobrien (int) nfs_version); 834174313Sobrien } 835174313Sobrien if (!nfs_proto) { 836174313Sobrien#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) 837174313Sobrien nfs_proto = "tcp"; 838174313Sobrien#else /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ 839174313Sobrien nfs_proto = "udp"; 840174313Sobrien#endif /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ 841174313Sobrien plog(XLOG_INFO, "No NFS protocol transport specified, will use %s", 842174313Sobrien nfs_proto); 843174313Sobrien } 844174313Sobrien } else { 84538494Sobrien /* 84638494Sobrien * Find the best combination of NFS version and protocol. 84738494Sobrien * When given a choice, use the highest available version, 84838494Sobrien * and use TCP over UDP if available. 84938494Sobrien */ 850174313Sobrien if (check_pmap_up(host, ip)) { 851174313Sobrien if (nfs_proto) { 852174313Sobrien best_nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto); 853174313Sobrien nfs_port = ip->sin_port; 854174313Sobrien } 855174313Sobrien#ifdef MNTTAB_OPT_PROTO 856174313Sobrien else { 857174313Sobrien u_int proto_nfs_version; 858174313Sobrien char **p; 85938494Sobrien 860174313Sobrien for (p = protocols; *p; p++) { 861174313Sobrien proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p); 86238494Sobrien 863174313Sobrien if (proto_nfs_version > best_nfs_version) { 864174313Sobrien best_nfs_version = proto_nfs_version; 865174313Sobrien nfs_proto = *p; 866174313Sobrien nfs_port = ip->sin_port; 867174313Sobrien } 86838494Sobrien } 86938494Sobrien } 870174313Sobrien#endif /* MNTTAB_OPT_PROTO */ 871174313Sobrien } else { 872174313Sobrien plog(XLOG_INFO, "portmapper service not running on %s", host); 87338494Sobrien } 87438494Sobrien 875174313Sobrien /* use the portmapper results only nfs_version is not set yet */ 876174313Sobrien if (!best_nfs_version) { 87738494Sobrien /* 87838494Sobrien * If the NFS server is down or does not support the portmapper call 87938494Sobrien * (such as certain Novell NFS servers) we mark it as version 2 and we 880174313Sobrien * let the nfs code deal with the case when it is down. If/when the 881174313Sobrien * server comes back up and it can support NFSv3 and/or TCP, it will 88238494Sobrien * use those. 88338494Sobrien */ 884174313Sobrien if (nfs_version == 0) { 885174313Sobrien nfs_version = NFS_VERSION; 886174313Sobrien nfs_proto = "udp"; 887174313Sobrien } 888174313Sobrien plog(XLOG_INFO, "NFS service not running on %s", host); 889174313Sobrien fserver_is_down = 1; 890174313Sobrien } else { 891174313Sobrien if (nfs_version == 0) 892174313Sobrien nfs_version = best_nfs_version; 893174313Sobrien plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s", 894174313Sobrien (int) nfs_version, nfs_proto, host); 89538494Sobrien } 89638494Sobrien } 89738494Sobrien 898174313Sobrien /* 899174313Sobrien * Determine the NFS port. 900174313Sobrien * 901174313Sobrien * A valid "port" mount option overrides anything else. 902174313Sobrien * If the port has been determined from the portmapper, use that. 903174313Sobrien * Default to NFS_PORT otherwise (cf. RFC 2054, 3). 904174313Sobrien */ 905174313Sobrien nfs_port_opt = hasmntval(&mnt, MNTTAB_OPT_PORT); 906174313Sobrien if (nfs_port_opt > 0) 907174313Sobrien nfs_port = htons(nfs_port_opt); 908174313Sobrien if (!nfs_port) 909174313Sobrien nfs_port = htons(NFS_PORT); 91038494Sobrien 911174313Sobrien dlog("find_nfs_srvr: using port %d for nfs on %s", 912174313Sobrien (int) ntohs(nfs_port), host); 913174313Sobrien ip->sin_port = nfs_port; 91438494Sobrien 915174313Sobrienno_dns: 91638494Sobrien /* 91742633Sobrien * Try to find an existing fs server structure for this host. 91838494Sobrien * Note that differing versions or protocols have their own structures. 91938494Sobrien * XXX: Need to fix the ping mechanism to actually use the NFS protocol 92038494Sobrien * chosen here (right now it always uses datagram sockets). 92138494Sobrien */ 92238494Sobrien ITER(fs, fserver, &nfs_srvr_list) { 92338494Sobrien if (STREQ(host, fs->fs_host) && 92438494Sobrien nfs_version == fs->fs_version && 92538494Sobrien STREQ(nfs_proto, fs->fs_proto)) { 92638494Sobrien /* 927174313Sobrien * fill in the IP address -- this is only needed 928174313Sobrien * if there is a chance an IP address will change 929174313Sobrien * between mounts. 930174313Sobrien * Mike Mitchell, mcm@unx.sas.com, 09/08/93 93138494Sobrien */ 932174313Sobrien if (hp && fs->fs_ip && 933174313Sobrien memcmp((voidp) &fs->fs_ip->sin_addr, 934174313Sobrien (voidp) hp->h_addr, 935174313Sobrien sizeof(fs->fs_ip->sin_addr)) != 0) { 936174313Sobrien struct in_addr ia; 937174313Sobrien char *old_ipaddr, *new_ipaddr; 938174313Sobrien old_ipaddr = strdup(inet_ntoa(fs->fs_ip->sin_addr)); 939174313Sobrien memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr)); 940174313Sobrien new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */ 941174313Sobrien plog(XLOG_WARNING, "fileserver %s changed ip: %s -> %s", 942174313Sobrien fs->fs_host, old_ipaddr, new_ipaddr); 943174313Sobrien XFREE(old_ipaddr); 944174313Sobrien flush_nfs_fhandle_cache(fs); 945174313Sobrien memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr)); 946174313Sobrien } 947174313Sobrien 948174313Sobrien /* 949174313Sobrien * If the new file systems doesn't use WebNFS, the nfs pings may 950174313Sobrien * try to contact the portmapper. 951174313Sobrien */ 952174313Sobrien if (!(mf->mf_flags & MFF_WEBNFS)) 953174313Sobrien fs->fs_flags &= ~FSF_WEBNFS; 954174313Sobrien 955174313Sobrien /* check if pingval needs to be updated/set/reset */ 956174313Sobrien start_nfs_pings(fs, pingval); 957174313Sobrien 958174313Sobrien /* 959174313Sobrien * Following if statement from Mike Mitchell <mcm@unx.sas.com> 960174313Sobrien * Initialize the ping data if we aren't pinging now. The np_ttl and 961174313Sobrien * np_ping fields are especially important. 962174313Sobrien */ 96338494Sobrien if (!(fs->fs_flags & FSF_PINGING)) { 96438494Sobrien np = (nfs_private *) fs->fs_private; 96538494Sobrien np->np_mountd_inval = TRUE; 966174313Sobrien np->np_xid = XID_ALLOC(); 96738494Sobrien np->np_error = -1; 96838494Sobrien np->np_ping = 0; 96938494Sobrien /* 97038494Sobrien * Initially the server will be deemed dead 97138494Sobrien * after MAX_ALLOWED_PINGS of the fast variety 97238494Sobrien * have failed. 97338494Sobrien */ 974174313Sobrien np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime(NULL) - 1; 975174313Sobrien start_nfs_pings(fs, pingval); 976174313Sobrien if (fserver_is_down) 977174313Sobrien fs->fs_flags |= FSF_VALID | FSF_DOWN; 97838494Sobrien } 97938494Sobrien 98038494Sobrien fs->fs_refc++; 98138494Sobrien if (ip) 98238494Sobrien XFREE(ip); 98338494Sobrien return fs; 98438494Sobrien } 98538494Sobrien } 98638494Sobrien 98738494Sobrien /* 98838494Sobrien * Get here if we can't find an entry 98938494Sobrien */ 99038494Sobrien 99138494Sobrien /* 99238494Sobrien * Allocate a new server 99338494Sobrien */ 99438494Sobrien fs = ALLOC(struct fserver); 99538494Sobrien fs->fs_refc = 1; 99638494Sobrien fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname"); 99738494Sobrien if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) 99838494Sobrien host_normalize(&fs->fs_host); 99938494Sobrien fs->fs_ip = ip; 100038494Sobrien fs->fs_cid = 0; 100138494Sobrien if (ip) { 100238494Sobrien fs->fs_flags = FSF_DOWN; /* Starts off down */ 100338494Sobrien } else { 100438494Sobrien fs->fs_flags = FSF_ERROR | FSF_VALID; 100538494Sobrien mf->mf_flags |= MFF_ERROR; 100638494Sobrien mf->mf_error = ENOENT; 100738494Sobrien } 1008174313Sobrien if (mf->mf_flags & MFF_WEBNFS) 1009174313Sobrien fs->fs_flags |= FSF_WEBNFS; 101038494Sobrien fs->fs_version = nfs_version; 101138494Sobrien fs->fs_proto = nfs_proto; 101238494Sobrien fs->fs_type = MNTTAB_TYPE_NFS; 101338494Sobrien fs->fs_pinger = AM_PINGER; 1014174313Sobrien fs->fs_flags |= FSF_PING_UNINIT; /* pinger hasn't been initialized */ 101538494Sobrien np = ALLOC(struct nfs_private); 101638494Sobrien memset((voidp) np, 0, sizeof(*np)); 101738494Sobrien np->np_mountd_inval = TRUE; 1018174313Sobrien np->np_xid = XID_ALLOC(); 101938494Sobrien np->np_error = -1; 102038494Sobrien 102138494Sobrien /* 102238494Sobrien * Initially the server will be deemed dead after 102338494Sobrien * MAX_ALLOWED_PINGS of the fast variety have failed. 102438494Sobrien */ 1025174313Sobrien np->np_ttl = clocktime(NULL) + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1; 102638494Sobrien fs->fs_private = (voidp) np; 102738494Sobrien fs->fs_prfree = (void (*)(voidp)) free; 102838494Sobrien 1029174313Sobrien if (!FSRV_ERROR(fs)) { 1030174313Sobrien /* start of keepalive timer, first updating pingval */ 103138494Sobrien start_nfs_pings(fs, pingval); 1032174313Sobrien if (fserver_is_down) 1033174313Sobrien fs->fs_flags |= FSF_VALID | FSF_DOWN; 103438494Sobrien } 103538494Sobrien 103638494Sobrien /* 103738494Sobrien * Add to list of servers 103838494Sobrien */ 103938494Sobrien ins_que(&fs->fs_q, &nfs_srvr_list); 104038494Sobrien 104138494Sobrien return fs; 104238494Sobrien} 1043