BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.sbin / amd / amd / srvr_nfs.c
index 0d91788..1afd45c 100644 (file)
@@ -1,6 +1,4 @@
 /*
 /*
- * $Id: srvr_nfs.c,v 5.2 90/06/23 22:20:02 jsp Rel $
- *
  * Copyright (c) 1990 Jan-Simon Pendry
  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  * Copyright (c) 1990 The Regents of the University of California.
  * Copyright (c) 1990 Jan-Simon Pendry
  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  * Copyright (c) 1990 The Regents of the University of California.
@@ -9,21 +7,38 @@
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry at Imperial College, London.
  *
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry at Imperial College, London.
  *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * Neither the name of the University nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)srvr_nfs.c  5.3 (Berkeley) 5/12/91
+ *
+ * $Id: srvr_nfs.c,v 5.2.1.6 91/05/07 22:18:36 jsp Alpha $
  *
  *
- *     @(#)srvr_nfs.c  5.1 (Berkeley) 6/29/90
  */
 
 /*
  */
 
 /*
@@ -40,7 +55,7 @@ qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
 
 typedef struct nfs_private {
        u_short np_mountd;      /* Mount daemon port number */
 
 typedef struct nfs_private {
        u_short np_mountd;      /* Mount daemon port number */
-       char np_mountd_inval;   /* Port may be invalid */
+       char np_mountd_inval;   /* Port *may* be invalid */
        int np_ping;            /* Number of failed ping attempts */
        time_t np_ttl;          /* Time when server is thought dead */
        int np_xid;             /* RPC transaction id for pings */
        int np_ping;            /* Number of failed ping attempts */
        time_t np_ttl;          /* Time when server is thought dead */
        int np_xid;             /* RPC transaction id for pings */
@@ -75,9 +90,27 @@ static int np_xid;   /* For NFS pings */
 static int ping_len;
 static char ping_buf[sizeof(struct rpc_msg) + 32];
 
 static int ping_len;
 static char ping_buf[sizeof(struct rpc_msg) + 32];
 
+/*
+ * Flush any cached data
+ */
+void flush_srvr_nfs_cache P((void));
+void flush_srvr_nfs_cache()
+{
+       fserver *fs = 0;
+
+       ITER(fs, fserver, &nfs_srvr_list) {
+               nfs_private *np = (nfs_private *) fs->fs_private;
+               if (np) {
+                       np->np_mountd_inval = TRUE;
+                       np->np_error = -1;
+               }
+       }
+}
+
 /*
  * Startup the NFS ping
  */
 /*
  * Startup the NFS ping
  */
+static void start_ping(P_void);
 static void start_ping()
 {
        XDR ping_xdr;
 static void start_ping()
 {
        XDR ping_xdr;
@@ -113,15 +146,22 @@ static void start_ping()
 /*
  * Called when a portmap reply arrives
  */
 /*
  * Called when a portmap reply arrives
  */
+/*ARGSUSED*/
+static void got_portmap P((voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done));
 static void got_portmap(pkt, len, sa, ia, idv, done)
 voidp pkt;
 int len;
 static void got_portmap(pkt, len, sa, ia, idv, done)
 voidp pkt;
 int len;
-struct sockaddr_in *sa, *ia;
+struct sockaddr_in *sa;
+struct sockaddr_in *ia;
 voidp idv;
 int done;
 {
        fserver *fs2 = (fserver *) idv;
        fserver *fs = 0;
 voidp idv;
 int done;
 {
        fserver *fs2 = (fserver *) idv;
        fserver *fs = 0;
+
+       /*
+        * Find which fileserver we are talking about
+        */
        ITER(fs, fserver, &nfs_srvr_list)
                if (fs == fs2)
                        break;
        ITER(fs, fserver, &nfs_srvr_list)
                if (fs == fs2)
                        break;
@@ -168,6 +208,7 @@ int done;
 /*
  * Obtain portmap information
  */
 /*
  * Obtain portmap information
  */
+static int call_portmap P((fserver *fs, AUTH *auth, unsigned long prog, unsigned long vers, unsigned long prot));
 static int call_portmap(fs, auth, prog, vers, prot)
 fserver *fs;
 AUTH *auth;
 static int call_portmap(fs, auth, prog, vers, prot)
 fserver *fs;
 AUTH *auth;
@@ -205,11 +246,16 @@ static void recompute_portmap P((fserver *fs));
 static void recompute_portmap(fs)
 fserver *fs;
 {                              
 static void recompute_portmap(fs)
 fserver *fs;
 {                              
-       if (!nfs_auth)
-               nfs_auth = authunix_create_default();
-       if (!nfs_auth) {
+       int error;
+
+       if (nfs_auth)
+               error = 0;
+       else
+               error = make_nfs_auth();
+
+       if (error) {
                nfs_private *np = (nfs_private *) fs->fs_private;
                nfs_private *np = (nfs_private *) fs->fs_private;
-               np->np_error = ENOBUFS;
+               np->np_error = error;
        } else {
                call_portmap(fs, nfs_auth, MOUNTPROG,
                        MOUNTVERS, (unsigned long) IPPROTO_UDP);
        } else {
                call_portmap(fs, nfs_auth, MOUNTPROG,
                        MOUNTVERS, (unsigned long) IPPROTO_UDP);
@@ -222,16 +268,20 @@ fserver *fs;
  * structure when the ping was transmitted.
  */
 /*ARGSUSED*/
  * structure when the ping was transmitted.
  */
 /*ARGSUSED*/
+static void nfs_pinged P((voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done));
 static void nfs_pinged(pkt, len, sp, tsp, idv, done)
 voidp pkt;
 int len;
 static void nfs_pinged(pkt, len, sp, tsp, idv, done)
 voidp pkt;
 int len;
-struct sockaddr_in *sp, *tsp;
+struct sockaddr_in *sp;
+struct sockaddr_in *tsp;
 voidp idv;
 int done;
 {
        int xid = (int) idv;
        fserver *fs;
 voidp idv;
 int done;
 {
        int xid = (int) idv;
        fserver *fs;
+#ifdef DEBUG
        int found_map = 0;
        int found_map = 0;
+#endif /* DEBUG */
 
        if (!done)
                return;
 
        if (!done)
                return;
@@ -252,7 +302,12 @@ int done;
                                if (fs->fs_flags & FSF_VALID) {
                                        srvrlog(fs, "is up");
                                } else {
                                if (fs->fs_flags & FSF_VALID) {
                                        srvrlog(fs, "is up");
                                } else {
-                                       srvrlog(fs, "ok");
+                                       if (np->np_ping > 1)
+                                               srvrlog(fs, "ok");
+#ifdef DEBUG
+                                       else
+                                               srvrlog(fs, "starts up");
+#endif
                                        fs->fs_flags |= FSF_VALID;
                                }
 
                                        fs->fs_flags |= FSF_VALID;
                                }
 
@@ -261,13 +316,15 @@ int done;
                                if (fs->fs_flags & FSF_WANT)
                                        wakeup_srvr(fs);
 #endif /* notdef */
                                if (fs->fs_flags & FSF_WANT)
                                        wakeup_srvr(fs);
 #endif /* notdef */
+                               map_flush_srvr(fs);
                        } else {
                                if (fs->fs_flags & FSF_VALID) {
 #ifdef DEBUG
                                        dlog("file server %s type nfs is still up", fs->fs_host);
 #endif /* DEBUG */
                                } else {
                        } else {
                                if (fs->fs_flags & FSF_VALID) {
 #ifdef DEBUG
                                        dlog("file server %s type nfs is still up", fs->fs_host);
 #endif /* DEBUG */
                                } else {
-                                       srvrlog(fs, "ok");
+                                       if (np->np_ping > 1)
+                                               srvrlog(fs, "ok");
                                        fs->fs_flags |= FSF_VALID;
                                }
                        }
                                        fs->fs_flags |= FSF_VALID;
                                }
                        }
@@ -300,7 +357,9 @@ int done;
                        if (np->np_mountd_inval)
                                recompute_portmap(fs);
 
                        if (np->np_mountd_inval)
                                recompute_portmap(fs);
 
+#ifdef DEBUG   
                        found_map++;
                        found_map++;
+#endif /* DEBUG */
                        break;
                }
        }
                        break;
                }
        }
@@ -320,31 +379,31 @@ fserver *fs;
 {
        nfs_private *np = (nfs_private *) fs->fs_private;
 
 {
        nfs_private *np = (nfs_private *) fs->fs_private;
 
+       /*
+        * Another ping has failed
+        */
+       np->np_ping++;
+
        /*
         * Not known to be up any longer
         */
        if (FSRV_ISUP(fs)) {
                fs->fs_flags &= ~FSF_VALID;
        /*
         * Not known to be up any longer
         */
        if (FSRV_ISUP(fs)) {
                fs->fs_flags &= ~FSF_VALID;
-               srvrlog(fs, "not responding");
+               if (np->np_ping > 1)
+                       srvrlog(fs, "not responding");
        }
 
        }
 
-       /*
-        * Another ping has failed
-        */
-       np->np_ping++;
-
        /*
         * If ttl has expired then guess that it is dead
         */
        if (np->np_ttl < clocktime()) {
        /*
         * If ttl has expired then guess that it is dead
         */
        if (np->np_ttl < clocktime()) {
+               int oflags = fs->fs_flags;
                if ((fs->fs_flags & FSF_DOWN) == 0) {
                        /*
                         * Server was up, but is now down.
                         */
                        srvrlog(fs, "is down");
                        fs->fs_flags |= FSF_DOWN|FSF_VALID;
                if ((fs->fs_flags & FSF_DOWN) == 0) {
                        /*
                         * Server was up, but is now down.
                         */
                        srvrlog(fs, "is down");
                        fs->fs_flags |= FSF_DOWN|FSF_VALID;
-                       if (fs->fs_flags & FSF_WANT)
-                               wakeup_srvr(fs);
                        /*
                         * Since the server is down, the portmap
                         * information may now be wrong, so it
                        /*
                         * Since the server is down, the portmap
                         * information may now be wrong, so it
@@ -352,16 +411,24 @@ fserver *fs;
                         */
                        flush_nfs_fhandle_cache(fs);
                        np->np_error = -1;
                         */
                        flush_nfs_fhandle_cache(fs);
                        np->np_error = -1;
+#ifdef notdef
                        /*
                         * Pretend just one ping has failed now
                         */
                        np->np_ping = 1;
                        /*
                         * Pretend just one ping has failed now
                         */
                        np->np_ping = 1;
+#endif
                } else {
                        /*
                         * Known to be down
                         */
                } else {
                        /*
                         * Known to be down
                         */
+#ifdef DEBUG
+                       if ((fs->fs_flags & FSF_VALID) == 0)
+                               srvrlog(fs, "starts down");
+#endif
                        fs->fs_flags |= FSF_VALID;
                }
                        fs->fs_flags |= FSF_VALID;
                }
+               if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT))
+                       wakeup_srvr(fs);
        } else {
 #ifdef DEBUG
                if (np->np_ping > 1)
        } else {
 #ifdef DEBUG
                if (np->np_ping > 1)
@@ -454,6 +521,7 @@ fserver *fs;
        fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs);
 }
 
        fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs);
 }
 
+int nfs_srvr_port P((fserver *fs, u_short *port, voidp wchan));
 int nfs_srvr_port(fs, port, wchan)
 fserver *fs;
 u_short *port;
 int nfs_srvr_port(fs, port, wchan)
 fserver *fs;
 u_short *port;
@@ -465,16 +533,21 @@ voidp wchan;
                        nfs_private *np = (nfs_private *) fs->fs_private;
                        if (np->np_error == 0) {
                                *port = np->np_mountd;
                        nfs_private *np = (nfs_private *) fs->fs_private;
                        if (np->np_error == 0) {
                                *port = np->np_mountd;
-                               /*
-                                * Now go get it again in case it changed
-                                */
-                               np->np_mountd_inval = TRUE;
                                error = 0;
                        } else {
                                error = 0;
                        } else {
-                               if (np->np_error < 0)
-                                       recompute_portmap(fs);
                                error = np->np_error;
                        }
                                error = np->np_error;
                        }
+                       /*
+                        * Now go get the port mapping again in case it changed.
+                        * Note that it is used even if (np_mountd_inval)
+                        * is True.  The flag is used simply as an
+                        * indication that the mountd may be invalid, not
+                        * that it is known to be invalid.
+                        */
+                       if (np->np_mountd_inval)
+                               recompute_portmap(fs);
+                       else
+                               np->np_mountd_inval = TRUE;
                } else {
                        error = EWOULDBLOCK;
                }
                } else {
                        error = EWOULDBLOCK;
                }
@@ -538,7 +611,7 @@ mntfs *mf;
         * are required or not.  < 0 = no pings.
         */
        { struct mntent mnt;
         * are required or not.  < 0 = no pings.
         */
        { struct mntent mnt;
-         mnt.mnt_opts = mf->mf_fo->opt_opts;
+         mnt.mnt_opts = mf->mf_mopts;
          pingval = hasmntval(&mnt, "ping");
 #ifdef HAS_TCP_NFS
          /*
          pingval = hasmntval(&mnt, "ping");
 #ifdef HAS_TCP_NFS
          /*
@@ -552,11 +625,20 @@ mntfs *mf;
        }
 
 
        }
 
 
-top:
        /*
        /*
-        * Scan the list of known servers looking
-        * for one with the same name
+        * lookup host address and canonical name
+        */
+       hp = gethostbyname(host);
+
+       /*
+        * New code from Bob Harris <harris@basil-rathbone.mit.edu>
+        * Use canonical name to keep track of file server
+        * information.  This way aliases do not generate
+        * multiple NFS pingers.  (Except when we're normalizing
+        * hosts.)
         */
         */
+       if (hp && !normalize_hosts) host = hp->h_name;
+
        ITER(fs, fserver, &nfs_srvr_list) {
                if (STREQ(host, fs->fs_host)) {
                        start_nfs_pings(fs, pingval);
        ITER(fs, fserver, &nfs_srvr_list) {
                if (STREQ(host, fs->fs_host)) {
                        start_nfs_pings(fs, pingval);
@@ -565,22 +647,7 @@ top:
                }
        }
 
                }
        }
 
-       /*
-        * If the name is not known, it may be
-        * because it was an alternate name for
-        * the same machine.  So do a lookup and
-        * try again with the primary name if that
-        * is different.
-        * All that assuming it wasn't normalized
-        * earlier of course...
-        */
-       if (hp == 0) {
-               hp = gethostbyname(host);
-               if (hp && !STREQ(host, hp->h_name) && !normalize_hosts) {
-                       host = hp->h_name;
-                       goto top;
-               }
-       }
+
 
        /*
         * Get here if we can't find an entry
 
        /*
         * Get here if we can't find an entry
@@ -591,7 +658,8 @@ top:
                        ip = ALLOC(sockaddr_in);
                        bzero((voidp) ip, sizeof(*ip));
                        ip->sin_family = AF_INET;
                        ip = ALLOC(sockaddr_in);
                        bzero((voidp) ip, sizeof(*ip));
                        ip->sin_family = AF_INET;
-                       ip->sin_addr = *(struct in_addr *) hp->h_addr;
+                       bcopy((voidp) hp->h_addr, (voidp) &ip->sin_addr, sizeof(ip->sin_addr));
+
                        ip->sin_port = htons(NFS_PORT);
                        break;
 
                        ip->sin_port = htons(NFS_PORT);
                        break;
 
@@ -600,6 +668,7 @@ top:
                        break;
                }
        } else {
                        break;
                }
        } else {
+               plog(XLOG_USER, "Unknown host: %s", host);
                ip = 0;
        }
 
                ip = 0;
        }
 
@@ -609,7 +678,7 @@ top:
        fs = ALLOC(fserver);
        fs->fs_refc = 1;
        fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
        fs = ALLOC(fserver);
        fs->fs_refc = 1;
        fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
-       host_normalize(&fs->fs_host);
+       if (normalize_hosts) host_normalize(&fs->fs_host);
        fs->fs_ip = ip;
        fs->fs_cid = 0;
        if (ip) {
        fs->fs_ip = ip;
        fs->fs_cid = 0;
        if (ip) {