144626Smckusick /*
244626Smckusick * Copyright (c) 1990 Jan-Simon Pendry
344626Smckusick * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4*61776Sbostic * Copyright (c) 1990, 1993
5*61776Sbostic * The Regents of the University of California. All rights reserved.
644626Smckusick *
744626Smckusick * This code is derived from software contributed to Berkeley by
844626Smckusick * Jan-Simon Pendry at Imperial College, London.
944626Smckusick *
1044626Smckusick * %sccs.include.redist.c%
1144626Smckusick *
12*61776Sbostic * @(#)srvr_nfs.c 8.1 (Berkeley) 06/06/93
1349683Spendry *
1452460Spendry * $Id: srvr_nfs.c,v 5.2.2.1 1992/02/09 15:09:06 jsp beta $
1549683Spendry *
1644626Smckusick */
1744626Smckusick
1844626Smckusick /*
1944626Smckusick * NFS server modeling
2044626Smckusick */
2144626Smckusick
2244626Smckusick #include "am.h"
2344626Smckusick #include <netdb.h>
2444626Smckusick #include <rpc/pmap_prot.h>
2544626Smckusick #include "mount.h"
2644626Smckusick
2744626Smckusick extern qelem nfs_srvr_list;
2844626Smckusick qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
2944626Smckusick
3044626Smckusick typedef struct nfs_private {
3144626Smckusick u_short np_mountd; /* Mount daemon port number */
3247526Spendry char np_mountd_inval; /* Port *may* be invalid */
3344626Smckusick int np_ping; /* Number of failed ping attempts */
3444626Smckusick time_t np_ttl; /* Time when server is thought dead */
3544626Smckusick int np_xid; /* RPC transaction id for pings */
3644626Smckusick int np_error; /* Error during portmap request */
3744626Smckusick } nfs_private;
3844626Smckusick
3944626Smckusick static int np_xid; /* For NFS pings */
4044626Smckusick #define NPXID_ALLOC() (++np_xid)
4144626Smckusick /*#define NPXID_ALLOC() ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/
4244626Smckusick
4344626Smckusick /*
4444626Smckusick * Number of pings allowed to fail before host is declared down
4544626Smckusick * - three-fifths of the allowed mount time...
4644626Smckusick #define MAX_ALLOWED_PINGS ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER)
4744626Smckusick */
4844626Smckusick #define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1)
4944626Smckusick
5044626Smckusick /*
5144626Smckusick * How often to ping when starting a new server
5244626Smckusick */
5344626Smckusick #define FAST_NFS_PING 3
5444626Smckusick
5544626Smckusick #if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME
5644626Smckusick #error: sanity check failed
5744626Smckusick /*
5844626Smckusick you cannot do things this way...
5944626Smckusick sufficient fast pings must be given the chance to fail
6044626Smckusick within the allowed mount time
6144626Smckusick */
6244626Smckusick #endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */
6344626Smckusick
6444626Smckusick static int ping_len;
6544626Smckusick static char ping_buf[sizeof(struct rpc_msg) + 32];
6644626Smckusick
6744626Smckusick /*
6847526Spendry * Flush any cached data
6947526Spendry */
7047526Spendry void flush_srvr_nfs_cache P((void));
flush_srvr_nfs_cache()7147526Spendry void flush_srvr_nfs_cache()
7247526Spendry {
7347526Spendry fserver *fs = 0;
7447526Spendry
7547526Spendry ITER(fs, fserver, &nfs_srvr_list) {
7647526Spendry nfs_private *np = (nfs_private *) fs->fs_private;
7747526Spendry if (np) {
7847526Spendry np->np_mountd_inval = TRUE;
7947526Spendry np->np_error = -1;
8047526Spendry }
8147526Spendry }
8247526Spendry }
8347526Spendry
8447526Spendry /*
8544626Smckusick * Startup the NFS ping
8644626Smckusick */
8747526Spendry static void start_ping(P_void);
start_ping()8844626Smckusick static void start_ping()
8944626Smckusick {
9044626Smckusick XDR ping_xdr;
9144626Smckusick struct rpc_msg ping_msg;
9244626Smckusick
9344626Smckusick rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL);
9444626Smckusick
9544626Smckusick /*
9644626Smckusick * Create an XDR endpoint
9744626Smckusick */
9844626Smckusick xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE);
9944626Smckusick
10044626Smckusick /*
10144626Smckusick * Create the NFS ping message
10244626Smckusick */
10344626Smckusick if (!xdr_callmsg(&ping_xdr, &ping_msg)) {
10444626Smckusick plog(XLOG_ERROR, "Couldn't create ping RPC message");
10544626Smckusick going_down(3);
10644626Smckusick }
10744626Smckusick
10844626Smckusick /*
10944626Smckusick * Find out how long it is
11044626Smckusick */
11144626Smckusick ping_len = xdr_getpos(&ping_xdr);
11244626Smckusick
11344626Smckusick /*
11444626Smckusick * Destroy the XDR endpoint - we don't need it anymore
11544626Smckusick */
11644626Smckusick xdr_destroy(&ping_xdr);
11744626Smckusick }
11844626Smckusick
11944626Smckusick
12044626Smckusick /*
12144626Smckusick * Called when a portmap reply arrives
12244626Smckusick */
12347526Spendry /*ARGSUSED*/
12447526Spendry static void got_portmap P((voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done));
got_portmap(pkt,len,sa,ia,idv,done)12544626Smckusick static void got_portmap(pkt, len, sa, ia, idv, done)
12644626Smckusick voidp pkt;
12744626Smckusick int len;
12847526Spendry struct sockaddr_in *sa;
12947526Spendry struct sockaddr_in *ia;
13044626Smckusick voidp idv;
13144626Smckusick int done;
13244626Smckusick {
13344626Smckusick fserver *fs2 = (fserver *) idv;
13444626Smckusick fserver *fs = 0;
13547526Spendry
13647526Spendry /*
13747526Spendry * Find which fileserver we are talking about
13847526Spendry */
13944626Smckusick ITER(fs, fserver, &nfs_srvr_list)
14044626Smckusick if (fs == fs2)
14144626Smckusick break;
14244626Smckusick
14344626Smckusick if (fs == fs2) {
14444626Smckusick u_long port = 0; /* XXX - should be short but protocol is naff */
14544626Smckusick int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1;
14644626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
14744626Smckusick if (!error && port) {
14844626Smckusick #ifdef DEBUG
14944626Smckusick dlog("got port (%d) for mountd on %s", port, fs->fs_host);
15044626Smckusick #endif /* DEBUG */
15144626Smckusick /*
15244626Smckusick * Grab the port number. Portmap sends back
15344626Smckusick * an unsigned long in native ordering, so it
15444626Smckusick * needs converting to a unsigned short in
15544626Smckusick * network ordering.
15644626Smckusick */
15744626Smckusick np->np_mountd = htons((u_short) port);
15844626Smckusick np->np_mountd_inval = FALSE;
15944626Smckusick np->np_error = 0;
16044626Smckusick } else {
16144626Smckusick #ifdef DEBUG
16244626Smckusick dlog("Error fetching port for mountd on %s", fs->fs_host);
16344626Smckusick #endif /* DEBUG */
16444626Smckusick /*
16544626Smckusick * Almost certainly no mountd running on remote host
16644626Smckusick */
16744626Smckusick np->np_error = error ? error : ETIMEDOUT;
16844626Smckusick }
16944626Smckusick if (fs->fs_flags & FSF_WANT)
17044626Smckusick wakeup_srvr(fs);
17144626Smckusick } else if (done) {
17244626Smckusick #ifdef DEBUG
17344626Smckusick dlog("Got portmap for old port request");
17444626Smckusick #endif /* DEBUG */
17544626Smckusick } else {
17644626Smckusick #ifdef DEBUG
17744626Smckusick dlog("portmap request timed out");
17844626Smckusick #endif /* DEBUG */
17944626Smckusick }
18044626Smckusick }
18144626Smckusick
18244626Smckusick /*
18344626Smckusick * Obtain portmap information
18444626Smckusick */
18547526Spendry static int call_portmap P((fserver *fs, AUTH *auth, unsigned long prog, unsigned long vers, unsigned long prot));
call_portmap(fs,auth,prog,vers,prot)18644626Smckusick static int call_portmap(fs, auth, prog, vers, prot)
18744626Smckusick fserver *fs;
18844626Smckusick AUTH *auth;
18944626Smckusick unsigned long prog, vers, prot;
19044626Smckusick {
19144626Smckusick struct rpc_msg pmap_msg;
19244626Smckusick int len;
19344626Smckusick char iobuf[UDPMSGSIZE];
19444626Smckusick int error;
19544626Smckusick struct pmap pmap;
19644626Smckusick
19744626Smckusick rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0);
19844626Smckusick pmap.pm_prog = prog;
19944626Smckusick pmap.pm_vers = vers;
20044626Smckusick pmap.pm_prot = prot;
20144626Smckusick pmap.pm_port = 0;
20244626Smckusick len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT,
20344626Smckusick &pmap_msg, (voidp) &pmap, xdr_pmap, auth);
20444626Smckusick if (len > 0) {
20544626Smckusick struct sockaddr_in sin;
20644626Smckusick bzero((voidp) &sin, sizeof(sin));
20744626Smckusick sin = *fs->fs_ip;
20844626Smckusick sin.sin_port = htons(PMAPPORT);
20944626Smckusick error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
21044626Smckusick &sin, &sin, (voidp) fs, got_portmap);
21144626Smckusick } else {
21244626Smckusick error = -len;
21344626Smckusick }
21444626Smckusick return error;
21544626Smckusick }
21644626Smckusick
21744626Smckusick static void nfs_keepalive P((fserver*));
21844626Smckusick
21944626Smckusick static void recompute_portmap P((fserver *fs));
recompute_portmap(fs)22044626Smckusick static void recompute_portmap(fs)
22144626Smckusick fserver *fs;
22244626Smckusick {
22349683Spendry int error;
22449683Spendry
22549683Spendry if (nfs_auth)
22649683Spendry error = 0;
22749683Spendry else
22849683Spendry error = make_nfs_auth();
22949683Spendry
23049683Spendry if (error) {
23144626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
23249683Spendry np->np_error = error;
23344626Smckusick } else {
23444626Smckusick call_portmap(fs, nfs_auth, MOUNTPROG,
23544626Smckusick MOUNTVERS, (unsigned long) IPPROTO_UDP);
23644626Smckusick }
23744626Smckusick }
23844626Smckusick
23944626Smckusick /*
24044626Smckusick * This is called when we get a reply to an RPC ping.
24144626Smckusick * The value of id was taken from the nfs_private
24244626Smckusick * structure when the ping was transmitted.
24344626Smckusick */
24444626Smckusick /*ARGSUSED*/
24547526Spendry static void nfs_pinged P((voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done));
nfs_pinged(pkt,len,sp,tsp,idv,done)24644626Smckusick static void nfs_pinged(pkt, len, sp, tsp, idv, done)
24744626Smckusick voidp pkt;
24844626Smckusick int len;
24947526Spendry struct sockaddr_in *sp;
25047526Spendry struct sockaddr_in *tsp;
25144626Smckusick voidp idv;
25244626Smckusick int done;
25344626Smckusick {
25444626Smckusick int xid = (int) idv;
25544626Smckusick fserver *fs;
25647526Spendry #ifdef DEBUG
25744626Smckusick int found_map = 0;
25847526Spendry #endif /* DEBUG */
25944626Smckusick
26044626Smckusick if (!done)
26144626Smckusick return;
26244626Smckusick
26344626Smckusick /*
26444626Smckusick * For each node...
26544626Smckusick */
26644626Smckusick ITER(fs, fserver, &nfs_srvr_list) {
26744626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
26844626Smckusick if (np->np_xid == xid) {
26944626Smckusick /*
27044626Smckusick * Reset the ping counter.
27144626Smckusick * Update the keepalive timer.
27244626Smckusick * Log what happened.
27344626Smckusick */
27444626Smckusick if (fs->fs_flags & FSF_DOWN) {
27544626Smckusick fs->fs_flags &= ~FSF_DOWN;
27644626Smckusick if (fs->fs_flags & FSF_VALID) {
27744626Smckusick srvrlog(fs, "is up");
27844626Smckusick } else {
27947526Spendry if (np->np_ping > 1)
28047526Spendry srvrlog(fs, "ok");
28147526Spendry #ifdef DEBUG
28247526Spendry else
28347526Spendry srvrlog(fs, "starts up");
28447526Spendry #endif
28544626Smckusick fs->fs_flags |= FSF_VALID;
28644626Smckusick }
28744626Smckusick
28844626Smckusick #ifdef notdef
28944626Smckusick /* why ??? */
29044626Smckusick if (fs->fs_flags & FSF_WANT)
29144626Smckusick wakeup_srvr(fs);
29244626Smckusick #endif /* notdef */
29349683Spendry map_flush_srvr(fs);
29444626Smckusick } else {
29544626Smckusick if (fs->fs_flags & FSF_VALID) {
29644626Smckusick #ifdef DEBUG
29744626Smckusick dlog("file server %s type nfs is still up", fs->fs_host);
29844626Smckusick #endif /* DEBUG */
29944626Smckusick } else {
30047526Spendry if (np->np_ping > 1)
30147526Spendry srvrlog(fs, "ok");
30244626Smckusick fs->fs_flags |= FSF_VALID;
30344626Smckusick }
30444626Smckusick }
30544626Smckusick
30644626Smckusick /*
30744626Smckusick * Adjust ping interval
30844626Smckusick */
30944626Smckusick untimeout(fs->fs_cid);
31044626Smckusick fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs);
31144626Smckusick
31244626Smckusick /*
31344626Smckusick * Update ttl for this server
31444626Smckusick */
31544626Smckusick np->np_ttl = clocktime() +
31644626Smckusick (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1;
31744626Smckusick
31844626Smckusick /*
31944626Smckusick * New RPC xid...
32044626Smckusick */
32144626Smckusick np->np_xid = NPXID_ALLOC();
32244626Smckusick
32344626Smckusick /*
32444626Smckusick * Failed pings is zero...
32544626Smckusick */
32644626Smckusick np->np_ping = 0;
32744626Smckusick
32844626Smckusick /*
32944626Smckusick * Recompute portmap information if not known
33044626Smckusick */
33144626Smckusick if (np->np_mountd_inval)
33244626Smckusick recompute_portmap(fs);
33344626Smckusick
33447526Spendry #ifdef DEBUG
33544626Smckusick found_map++;
33647526Spendry #endif /* DEBUG */
33744626Smckusick break;
33844626Smckusick }
33944626Smckusick }
34044626Smckusick
34144626Smckusick #ifdef DEBUG
34244626Smckusick if (found_map == 0)
34344626Smckusick dlog("Spurious ping packet");
34444626Smckusick #endif /* DEBUG */
34544626Smckusick }
34644626Smckusick
34744626Smckusick /*
34844626Smckusick * Called when no ping-reply received
34944626Smckusick */
35044626Smckusick static void nfs_timed_out P((fserver *fs));
nfs_timed_out(fs)35144626Smckusick static void nfs_timed_out(fs)
35244626Smckusick fserver *fs;
35344626Smckusick {
35444626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
35544626Smckusick
35644626Smckusick /*
35747526Spendry * Another ping has failed
35847526Spendry */
35947526Spendry np->np_ping++;
36047526Spendry
36147526Spendry /*
36244626Smckusick * Not known to be up any longer
36344626Smckusick */
36444626Smckusick if (FSRV_ISUP(fs)) {
36544626Smckusick fs->fs_flags &= ~FSF_VALID;
36647526Spendry if (np->np_ping > 1)
36747526Spendry srvrlog(fs, "not responding");
36844626Smckusick }
36944626Smckusick
37044626Smckusick /*
37144626Smckusick * If ttl has expired then guess that it is dead
37244626Smckusick */
37344626Smckusick if (np->np_ttl < clocktime()) {
37449683Spendry int oflags = fs->fs_flags;
37544626Smckusick if ((fs->fs_flags & FSF_DOWN) == 0) {
37644626Smckusick /*
37744626Smckusick * Server was up, but is now down.
37844626Smckusick */
37944626Smckusick srvrlog(fs, "is down");
38044626Smckusick fs->fs_flags |= FSF_DOWN|FSF_VALID;
38144626Smckusick /*
38244626Smckusick * Since the server is down, the portmap
38344626Smckusick * information may now be wrong, so it
38444626Smckusick * must be flushed from the local cache
38544626Smckusick */
38644626Smckusick flush_nfs_fhandle_cache(fs);
38744626Smckusick np->np_error = -1;
38847526Spendry #ifdef notdef
38944626Smckusick /*
39044626Smckusick * Pretend just one ping has failed now
39144626Smckusick */
39244626Smckusick np->np_ping = 1;
39347526Spendry #endif
39444626Smckusick } else {
39544626Smckusick /*
39644626Smckusick * Known to be down
39744626Smckusick */
39847526Spendry #ifdef DEBUG
39949683Spendry if ((fs->fs_flags & FSF_VALID) == 0)
40049683Spendry srvrlog(fs, "starts down");
40147526Spendry #endif
40249683Spendry fs->fs_flags |= FSF_VALID;
40344626Smckusick }
40449683Spendry if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT))
40547526Spendry wakeup_srvr(fs);
40644626Smckusick } else {
40744626Smckusick #ifdef DEBUG
40844626Smckusick if (np->np_ping > 1)
40944626Smckusick dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS);
41044626Smckusick #endif /* DEBUG */
41144626Smckusick }
41244626Smckusick
41344626Smckusick /*
41444626Smckusick * Run keepalive again
41544626Smckusick */
41644626Smckusick nfs_keepalive(fs);
41744626Smckusick }
41844626Smckusick
41944626Smckusick /*
42044626Smckusick * Keep track of whether a server is alive
42144626Smckusick */
42244626Smckusick static void nfs_keepalive P((fserver *fs));
nfs_keepalive(fs)42344626Smckusick static void nfs_keepalive(fs)
42444626Smckusick fserver *fs;
42544626Smckusick {
42644626Smckusick int error;
42744626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
42844626Smckusick int fstimeo = -1;
42944626Smckusick
43044626Smckusick /*
43144626Smckusick * Send an NFS ping to this node
43244626Smckusick */
43344626Smckusick
43444626Smckusick if (ping_len == 0)
43544626Smckusick start_ping();
43644626Smckusick
43744626Smckusick /*
43844626Smckusick * Queue the packet...
43944626Smckusick */
44044626Smckusick error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf,
44144626Smckusick ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged);
44244626Smckusick
44344626Smckusick /*
44444626Smckusick * See if a hard error occured
44544626Smckusick */
44644626Smckusick switch (error) {
44744626Smckusick case ENETDOWN:
44844626Smckusick case ENETUNREACH:
44944626Smckusick case EHOSTDOWN:
45044626Smckusick case EHOSTUNREACH:
45144626Smckusick np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */
45244626Smckusick np->np_ttl = (time_t) 0;
45344626Smckusick /*
45444626Smckusick * This causes an immediate call to nfs_timed_out
45544626Smckusick * whenever the server was thought to be up.
45644626Smckusick * See +++ below.
45744626Smckusick */
45844626Smckusick fstimeo = 0;
45944626Smckusick break;
46044626Smckusick
46144626Smckusick case 0:
46244626Smckusick #ifdef DEBUG
46344626Smckusick dlog("Sent NFS ping to %s", fs->fs_host);
46444626Smckusick #endif /* DEBUG */
46544626Smckusick break;
46644626Smckusick }
46744626Smckusick
46844626Smckusick #ifdef DEBUG
46944626Smckusick /*dlog("keepalive, ping = %d", np->np_ping);*/
47044626Smckusick #endif /* DEBUG */
47144626Smckusick
47244626Smckusick /*
47344626Smckusick * Back off the ping interval if we are not getting replies and
47444626Smckusick * the remote system is know to be down.
47544626Smckusick */
47644626Smckusick switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) {
47744626Smckusick case FSF_VALID: /* Up */
47844626Smckusick if (fstimeo < 0) /* +++ see above */
47944626Smckusick fstimeo = FAST_NFS_PING;
48044626Smckusick break;
48144626Smckusick
48244626Smckusick case FSF_VALID|FSF_DOWN: /* Down */
48344626Smckusick fstimeo = fs->fs_pinger;
48444626Smckusick break;
48544626Smckusick
48644626Smckusick default: /* Unknown */
48744626Smckusick fstimeo = FAST_NFS_PING;
48844626Smckusick break;
48944626Smckusick }
49044626Smckusick
49144626Smckusick #ifdef DEBUG
49244626Smckusick dlog("NFS timeout in %d seconds", fstimeo);
49344626Smckusick #endif /* DEBUG */
49444626Smckusick
49544626Smckusick fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs);
49644626Smckusick }
49744626Smckusick
49847526Spendry int nfs_srvr_port P((fserver *fs, u_short *port, voidp wchan));
nfs_srvr_port(fs,port,wchan)49944626Smckusick int nfs_srvr_port(fs, port, wchan)
50044626Smckusick fserver *fs;
50144626Smckusick u_short *port;
50244626Smckusick voidp wchan;
50344626Smckusick {
50444626Smckusick int error = -1;
50544626Smckusick if ((fs->fs_flags & FSF_VALID) == FSF_VALID) {
50644626Smckusick if ((fs->fs_flags & FSF_DOWN) == 0) {
50744626Smckusick nfs_private *np = (nfs_private *) fs->fs_private;
50844626Smckusick if (np->np_error == 0) {
50944626Smckusick *port = np->np_mountd;
51044626Smckusick error = 0;
51144626Smckusick } else {
51244626Smckusick error = np->np_error;
51344626Smckusick }
51447526Spendry /*
51547526Spendry * Now go get the port mapping again in case it changed.
51647526Spendry * Note that it is used even if (np_mountd_inval)
51747526Spendry * is True. The flag is used simply as an
51847526Spendry * indication that the mountd may be invalid, not
51947526Spendry * that it is known to be invalid.
52047526Spendry */
52147526Spendry if (np->np_mountd_inval)
52247526Spendry recompute_portmap(fs);
52347526Spendry else
52447526Spendry np->np_mountd_inval = TRUE;
52544626Smckusick } else {
52644626Smckusick error = EWOULDBLOCK;
52744626Smckusick }
52844626Smckusick }
52944626Smckusick if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
53044626Smckusick /*
53144626Smckusick * If a wait channel is supplied, and no
53244626Smckusick * error has yet occured, then arrange
53344626Smckusick * that a wakeup is done on the wait channel,
53444626Smckusick * whenever a wakeup is done on this fs node.
53544626Smckusick * Wakeup's are done on the fs node whenever
53644626Smckusick * it changes state - thus causing control to
53744626Smckusick * come back here and new, better things to happen.
53844626Smckusick */
53944626Smckusick fs->fs_flags |= FSF_WANT;
54044626Smckusick sched_task(wakeup_task, wchan, (voidp) fs);
54144626Smckusick }
54244626Smckusick return error;
54344626Smckusick }
54444626Smckusick
54544626Smckusick static void start_nfs_pings P((fserver *fs, int pingval));
start_nfs_pings(fs,pingval)54644626Smckusick static void start_nfs_pings(fs, pingval)
54744626Smckusick fserver *fs;
54844626Smckusick int pingval;
54944626Smckusick {
55044626Smckusick if (!(fs->fs_flags & FSF_PINGING)) {
55144626Smckusick fs->fs_flags |= FSF_PINGING;
55244626Smckusick if (fs->fs_cid)
55344626Smckusick untimeout(fs->fs_cid);
55444626Smckusick if (pingval < 0) {
55544626Smckusick srvrlog(fs, "wired up");
55644626Smckusick fs->fs_flags |= FSF_VALID;
55744626Smckusick fs->fs_flags &= ~FSF_DOWN;
55844626Smckusick } else {
55944626Smckusick nfs_keepalive(fs);
56044626Smckusick }
56144626Smckusick } else {
56244626Smckusick #ifdef DEBUG
56344626Smckusick dlog("Already running pings to %s", fs->fs_host);
56444626Smckusick #endif /* DEBUG */
56544626Smckusick }
56644626Smckusick }
56744626Smckusick
56844626Smckusick /*
56944626Smckusick * Find an nfs server for a host.
57044626Smckusick */
57144626Smckusick fserver *find_nfs_srvr P((mntfs *mf));
find_nfs_srvr(mf)57244626Smckusick fserver *find_nfs_srvr(mf)
57344626Smckusick mntfs *mf;
57444626Smckusick {
57544626Smckusick fserver *fs;
57644626Smckusick struct hostent *hp = 0;
57744626Smckusick char *host = mf->mf_fo->opt_rhost;
57844626Smckusick struct sockaddr_in *ip;
57944626Smckusick nfs_private *np;
58044626Smckusick int pingval;
58144626Smckusick
58244626Smckusick /*
58344626Smckusick * Get ping interval from mount options.
58444626Smckusick * Current only used to decide whether pings
58544626Smckusick * are required or not. < 0 = no pings.
58644626Smckusick */
58744626Smckusick { struct mntent mnt;
58847526Spendry mnt.mnt_opts = mf->mf_mopts;
58944626Smckusick pingval = hasmntval(&mnt, "ping");
59044626Smckusick #ifdef HAS_TCP_NFS
59144626Smckusick /*
59244626Smckusick * Over TCP mount, don't bother to do pings.
59344626Smckusick * This is experimental - maybe you want to
59444626Smckusick * do pings anyway...
59544626Smckusick */
59644626Smckusick if (pingval == 0 && hasmntopt(&mnt, "tcp"))
59744626Smckusick pingval = -1;
59844626Smckusick #endif /* HAS_TCP_NFS */
59944626Smckusick }
60044626Smckusick
60144626Smckusick
60244626Smckusick /*
60347526Spendry * lookup host address and canonical name
60444626Smckusick */
60547526Spendry hp = gethostbyname(host);
60647526Spendry
60747526Spendry /*
60847526Spendry * New code from Bob Harris <harris@basil-rathbone.mit.edu>
60947526Spendry * Use canonical name to keep track of file server
61047526Spendry * information. This way aliases do not generate
61147526Spendry * multiple NFS pingers. (Except when we're normalizing
61247526Spendry * hosts.)
61347526Spendry */
61447526Spendry if (hp && !normalize_hosts) host = hp->h_name;
61547526Spendry
61644626Smckusick ITER(fs, fserver, &nfs_srvr_list) {
61744626Smckusick if (STREQ(host, fs->fs_host)) {
61844626Smckusick start_nfs_pings(fs, pingval);
61944626Smckusick fs->fs_refc++;
62044626Smckusick return fs;
62144626Smckusick }
62244626Smckusick }
62344626Smckusick
62444626Smckusick
62547526Spendry
62644626Smckusick /*
62744626Smckusick * Get here if we can't find an entry
62844626Smckusick */
62944626Smckusick if (hp) {
63044626Smckusick switch (hp->h_addrtype) {
63144626Smckusick case AF_INET:
63244626Smckusick ip = ALLOC(sockaddr_in);
63344626Smckusick bzero((voidp) ip, sizeof(*ip));
63444626Smckusick ip->sin_family = AF_INET;
63547526Spendry bcopy((voidp) hp->h_addr, (voidp) &ip->sin_addr, sizeof(ip->sin_addr));
63647526Spendry
63744626Smckusick ip->sin_port = htons(NFS_PORT);
63844626Smckusick break;
63944626Smckusick
64044626Smckusick default:
64144626Smckusick ip = 0;
64244626Smckusick break;
64344626Smckusick }
64444626Smckusick } else {
64547526Spendry plog(XLOG_USER, "Unknown host: %s", host);
64644626Smckusick ip = 0;
64744626Smckusick }
64844626Smckusick
64944626Smckusick /*
65044626Smckusick * Allocate a new server
65144626Smckusick */
65244626Smckusick fs = ALLOC(fserver);
65344626Smckusick fs->fs_refc = 1;
65444626Smckusick fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
65547526Spendry if (normalize_hosts) host_normalize(&fs->fs_host);
65644626Smckusick fs->fs_ip = ip;
65744626Smckusick fs->fs_cid = 0;
65844626Smckusick if (ip) {
65944626Smckusick fs->fs_flags = FSF_DOWN; /* Starts off down */
66044626Smckusick } else {
66144626Smckusick fs->fs_flags = FSF_ERROR|FSF_VALID;
66244626Smckusick mf->mf_flags |= MFF_ERROR;
66344626Smckusick mf->mf_error = ENOENT;
66444626Smckusick }
66544626Smckusick fs->fs_type = "nfs";
66644626Smckusick fs->fs_pinger = AM_PINGER;
66744626Smckusick np = ALLOC(nfs_private);
66844626Smckusick bzero((voidp) np, sizeof(*np));
66944626Smckusick np->np_mountd_inval = TRUE;
67044626Smckusick np->np_xid = NPXID_ALLOC();
67144626Smckusick np->np_error = -1;
67244626Smckusick /*
67344626Smckusick * Initially the server will be deemed dead after
67444626Smckusick * MAX_ALLOWED_PINGS of the fast variety have failed.
67544626Smckusick */
67644626Smckusick np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
67744626Smckusick fs->fs_private = (voidp) np;
67844626Smckusick fs->fs_prfree = (void (*)()) free;
67944626Smckusick
68044626Smckusick if (!(fs->fs_flags & FSF_ERROR)) {
68144626Smckusick /*
68244626Smckusick * Start of keepalive timer
68344626Smckusick */
68444626Smckusick start_nfs_pings(fs, pingval);
68544626Smckusick }
68644626Smckusick
68744626Smckusick /*
68844626Smckusick * Add to list of servers
68944626Smckusick */
69044626Smckusick ins_que(&fs->fs_q, &nfs_srvr_list);
69144626Smckusick
69244626Smckusick return fs;
69344626Smckusick }
694