svn commit: r358655 - head/sbin/mount_nfs

Gleb Smirnoff glebius at FreeBSD.org
Wed Mar 4 22:27:17 UTC 2020


Author: glebius
Date: Wed Mar  4 22:27:16 2020
New Revision: 358655
URL: https://svnweb.freebsd.org/changeset/base/358655

Log:
  When a machine boots the NFS mounting script is executed after
  interfaces are configured, but for many interfaces (e.g. all Intel)
  ifconfig causes link renegotiation, so the first attempt to mount
  NFS always fails. After that mount_nfs sleeps for 30 seconds, while
  only a couple seconds are actually required for interface to get up.
  
  Instead of sleeping, do select(2) on routing socket and check if
  some interface became UP and in this case retry immediately.
  
  Reviewed by:	rmacklem
  Differential Revision:	https://reviews.freebsd.org/D23934

Modified:
  head/sbin/mount_nfs/mount_nfs.c

Modified: head/sbin/mount_nfs/mount_nfs.c
==============================================================================
--- head/sbin/mount_nfs/mount_nfs.c	Wed Mar  4 22:23:24 2020	(r358654)
+++ head/sbin/mount_nfs/mount_nfs.c	Wed Mar  4 22:27:16 2020	(r358655)
@@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
 #include <fs/nfs/nfsv4_errstr.h>
 
 #include <arpa/inet.h>
+#include <net/route.h>
+#include <net/if.h>
 
 #include <ctype.h>
 #include <err.h>
@@ -505,6 +507,59 @@ sec_num_to_name(int flavor)
 	return (NULL);
 }
 
+/*
+ * Wait for RTM_IFINFO message with interface that is IFF_UP and with
+ * link on, or until timeout expires.  Returns seconds left.
+ */
+static time_t
+rtm_ifinfo_sleep(time_t sec)
+{
+	char buf[2048];
+	fd_set rfds;
+	struct timeval tv, start;
+	ssize_t nread;
+	int n, s;
+
+	s = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (s < 0)
+		err(EX_OSERR, "socket");
+	(void)gettimeofday(&start, NULL);
+
+	for (tv.tv_sec = sec, tv.tv_usec = 0;
+	    tv.tv_sec > 0;
+	    (void)gettimeofday(&tv, NULL),
+	    tv.tv_sec = sec - (tv.tv_sec - start.tv_sec)) {
+		FD_ZERO(&rfds);
+		FD_SET(s, &rfds);
+		n = select(s + 1, &rfds, NULL, NULL, &tv);
+		if (n == 0)
+			continue;
+		if (n == -1) {
+			if (errno == EINTR)
+				continue;
+			else
+				err(EX_SOFTWARE, "select");
+		}
+		nread = read(s, buf, 2048);
+		if (nread < 0)
+			err(EX_OSERR, "read");
+		if ((size_t)nread >= sizeof(struct if_msghdr)) {
+			struct if_msghdr *ifm;
+
+			ifm = (struct if_msghdr *)buf;
+			if (ifm->ifm_version == RTM_VERSION &&
+			    ifm->ifm_type == RTM_IFINFO &&
+			    (ifm->ifm_flags & IFF_UP) &&
+			    ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
+				break;
+		}
+	}
+
+	close(s);
+
+	return (tv.tv_sec);
+}
+
 static int
 getnfsargs(char *spec, struct iovec **iov, int *iovlen)
 {
@@ -638,7 +693,12 @@ getnfsargs(char *spec, struct iovec **iov, int *iovlen
 			if (daemon(0, 0) != 0)
 				err(1, "daemon");
 		}
-		sleep(60);
+		/*
+		 * If rtm_ifinfo_sleep() returns non-zero, don't count
+		 * that as a retry attempt.
+		 */
+		if (rtm_ifinfo_sleep(60) && retrycnt != 0)
+			retrycnt++;
 	}
 	freeaddrinfo(ai_nfs);
 


More information about the svn-src-head mailing list