Commit 031b174c authored by Mike Hibler's avatar Mike Hibler

Hopefully eliminate race in exports_setup when waiting for mountd to finish.

Changed mountd to write the current timestamp into /var/run/mountd.ts
whenever it has finished processing all exports files. So someone who
HUPs/USR1s mountd can check and see when the timestamp changes.

We use this in exports_setup.proxy to ensure we do not return before
mountd has completed parsing and effecting changes. Since I am too lazy
to check the before and after values of the timestamp, I just remove that
file just before signalling, and then wait for it to reappear to signify
that mountd is done.
parent 4a3b1cfc
diff -Nu mountd.orig/Makefile mountd/Makefile
--- mountd.orig/Makefile 2014-11-11 13:02:20.000000000 -0700
+++ mountd/Makefile 2015-01-13 14:25:40.369708874 -0700
+++ mountd/Makefile 2015-01-13 14:49:29.000000000 -0700
@@ -9,6 +9,9 @@
CFLAGS+= -I${MOUNT}
WARNS?= 2
......@@ -13,7 +13,7 @@ diff -Nu mountd.orig/Makefile mountd/Makefile
DPADD= ${LIBUTIL}
diff -Nu mountd.orig/mountd.c mountd/mountd.c
--- mountd.orig/mountd.c 2014-11-11 13:02:20.000000000 -0700
+++ mountd/mountd.c 2015-01-13 14:45:41.079684183 -0700
+++ mountd/mountd.c 2015-03-24 14:28:01.000000000 -0600
@@ -87,6 +87,31 @@
#include <stdarg.h>
#endif
......@@ -135,17 +135,18 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
struct exportlist *exphead;
struct mountlist *mlhead;
@@ -240,6 +287,9 @@
@@ -240,6 +287,10 @@
int dolog = 0;
int got_sighup = 0;
int xcreated = 0;
+#ifdef SPLIT_MOUNT
+int got_sigusr1 = 0;
+char *tsfile = "/var/run/mountd.ts";
+#endif
char *svcport_str = NULL;
static int mallocd_svcport = 0;
@@ -399,7 +449,7 @@
@@ -399,7 +450,7 @@
openlog("mountd", LOG_PID, LOG_DAEMON);
if (debug)
warnx("getting export list");
......@@ -154,7 +155,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (debug)
warnx("getting mount list");
get_mountlist();
@@ -411,6 +461,9 @@
@@ -411,6 +462,9 @@
signal(SIGQUIT, SIG_IGN);
}
signal(SIGHUP, huphandler);
......@@ -164,7 +165,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
signal(SIGTERM, terminate);
signal(SIGPIPE, SIG_IGN);
@@ -570,9 +623,15 @@
@@ -570,9 +624,15 @@
/* Expand svc_run() here so that we can call get_exportlist(). */
for (;;) {
if (got_sighup) {
......@@ -181,7 +182,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
readfds = svc_fdset;
switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) {
case -1:
@@ -951,6 +1010,9 @@
@@ -951,6 +1011,9 @@
sigemptyset(&sighup_mask);
sigaddset(&sighup_mask, SIGHUP);
......@@ -191,7 +192,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
saddr = svc_getrpccaller(transp)->buf;
switch (saddr->sa_family) {
case AF_INET6:
@@ -1227,6 +1289,9 @@
@@ -1227,6 +1290,9 @@
sigemptyset(&sighup_mask);
sigaddset(&sighup_mask, SIGHUP);
......@@ -201,7 +202,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
ep = exphead;
while (ep) {
@@ -1335,11 +1400,150 @@
@@ -1335,11 +1401,150 @@
int linesize;
FILE *exp_file;
......@@ -353,7 +354,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
{
struct exportlist *ep, *ep2;
struct grouplist *grp, *tgrp;
@@ -1352,9 +1556,11 @@
@@ -1352,9 +1557,11 @@
v4root_phase = 0;
dirhead = (struct dirlist *)NULL;
......@@ -365,7 +366,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
cp = line;
nextfield(&cp, &endcp);
if (*cp == '#')
@@ -1462,7 +1668,12 @@
@@ -1462,7 +1669,12 @@
* See if this directory is already
* in the list.
*/
......@@ -378,7 +379,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (ep == (struct exportlist *)NULL) {
ep = get_exp();
ep->ex_fs = fsb.f_fsid;
@@ -1504,6 +1715,7 @@
@@ -1504,6 +1716,7 @@
goto nextline;
}
......@@ -386,7 +387,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
/*
* Get the host or netgroup.
*/
@@ -1532,6 +1744,10 @@
@@ -1532,6 +1745,10 @@
} while (netgrp && getnetgrent(&hst, &usr, &dom));
endnetgrent();
*endcp = savedc;
......@@ -397,7 +398,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
}
cp = endcp;
nextfield(&cp, &endcp);
@@ -1582,11 +1798,17 @@
@@ -1582,11 +1799,17 @@
*/
grp = tgrp;
do {
......@@ -417,7 +418,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
} while (grp->gr_next && (grp = grp->gr_next));
/*
@@ -1610,6 +1832,7 @@
@@ -1610,6 +1833,7 @@
/*
* Success. Update the data structures.
*/
......@@ -425,7 +426,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (has_host) {
hang_dirp(dirhead, tgrp, ep, opt_flags);
grp->gr_next = grphead;
@@ -1617,13 +1840,22 @@
@@ -1617,13 +1841,22 @@
} else {
hang_dirp(dirhead, (struct grouplist *)NULL, ep,
opt_flags);
......@@ -448,7 +449,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
/*
* Insert in the list in alphabetical order.
*/
@@ -1634,8 +1866,15 @@
@@ -1634,8 +1867,15 @@
if (ep2)
ep->ex_next = ep2;
*epp = ep;
......@@ -464,7 +465,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
nextline:
v4root_phase = 0;
if (dirhead) {
@@ -1643,75 +1882,63 @@
@@ -1643,75 +1883,63 @@
dirhead = (struct dirlist *)NULL;
}
}
......@@ -577,7 +578,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (num > 0) {
build_iovec(&iov, &iovlen, "fstype", NULL, 0);
@@ -1723,7 +1950,10 @@
@@ -1723,7 +1951,10 @@
}
for (i = 0; i < num; i++) {
......@@ -589,7 +590,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
syslog(LOG_ERR, "getvfsbyname() failed for %s",
fsp->f_fstypename);
@@ -1752,6 +1982,7 @@
@@ -1752,6 +1983,7 @@
"can't delete exports for %s: %m %s",
fsp->f_mntonname, errmsg);
}
......@@ -597,7 +598,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
}
if (iov != NULL) {
@@ -1766,7 +1997,332 @@
@@ -1766,7 +1998,333 @@
/* free iov, allocated by realloc() */
free(iov);
iovlen = 0;
......@@ -867,6 +868,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
+#ifdef SPLIT_MOUNT
+ struct exportlist *Oexphead = NULL;
+ struct grouplist *Ogrphead = NULL;
+ FILE *tsfd;
+
+ if (incremental) {
+ if (debug)
......@@ -930,7 +932,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
/*
* Read in the exports file and build the list, calling
@@ -1780,7 +2336,7 @@
@@ -1780,7 +2338,7 @@
syslog(LOG_WARNING, "can't open %s", exnames[i]);
continue;
}
......@@ -939,7 +941,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
fclose(exp_file);
done++;
}
@@ -1789,6 +2345,28 @@
@@ -1789,6 +2347,28 @@
exit(2);
}
......@@ -968,7 +970,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
/*
* If there was no public fh, clear any previous one set.
*/
@@ -1797,6 +2375,72 @@
@@ -1797,6 +2377,83 @@
/* Resume the nfsd. If they weren't suspended, this is harmless. */
(void)nfssvc(NFSSVC_RESUMENFSD, NULL);
......@@ -992,6 +994,17 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
+ free_grp(tgrp);
+ }
+ }
+
+ /*
+ * Update a timestamp file so that anyone signalling us can tell
+ * when we have finished our work.
+ */
+ unlink(tsfile);
+ tsfd = fopen(tsfile, "w");
+ if (tsfd != NULL) {
+ fprintf(tsfd, "%lu\n", (unsigned long)time(NULL));
+ fclose(tsfd);
+ }
+#endif
+
+#ifdef MOUNTD_STATS
......@@ -1041,7 +1054,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
}
/*
@@ -1872,6 +2516,8 @@
@@ -1872,6 +2529,8 @@
{
struct dirlist *dp;
......@@ -1050,7 +1063,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
if (dp == (struct dirlist *)NULL)
out_of_mem();
@@ -2294,7 +2940,7 @@
@@ -2294,7 +2953,7 @@
ai->ai_flags |= AI_CANONNAME;
}
if (debug)
......@@ -1059,7 +1072,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
/*
* Sanity check: make sure we don't already have an entry
* for this host in the grouplist.
@@ -2385,7 +3031,8 @@
@@ -2385,7 +3044,8 @@
*/
int
do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
......@@ -1069,7 +1082,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
{
struct statfs fsb1;
struct addrinfo *ai;
@@ -2399,6 +3046,8 @@
@@ -2399,6 +3059,8 @@
int ret;
struct nfsex_args nfsea;
......@@ -1078,7 +1091,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (run_v4server > 0)
eap = &nfsea.export;
else
@@ -2504,7 +3153,34 @@
@@ -2504,7 +3166,34 @@
iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
errmsg[0] = '\0';
......@@ -1114,7 +1127,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
if (cp)
*cp-- = savedc;
else
@@ -2610,6 +3286,12 @@
@@ -2610,6 +3299,12 @@
/* free iov, allocated by realloc() */
free(iov);
}
......@@ -1127,7 +1140,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
return (ret);
}
@@ -3067,6 +3749,7 @@
@@ -3067,6 +3762,7 @@
/*
* Check an absolute directory path for any symbolic links. Return true
......@@ -1135,7 +1148,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
*/
int
check_dirpath(char *dirp)
@@ -3085,7 +3768,7 @@
@@ -3085,7 +3781,7 @@
}
cp++;
}
......@@ -1144,7 +1157,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
ret = 0;
return (ret);
}
@@ -3209,9 +3892,14 @@
@@ -3209,9 +3905,14 @@
}
void
......@@ -1161,7 +1174,7 @@ diff -Nu mountd.orig/mountd.c mountd/mountd.c
}
void terminate(int sig __unused)
@@ -3221,4 +3909,3 @@
@@ -3221,4 +3922,3 @@
rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
exit (0);
}
......
......@@ -625,10 +625,6 @@ if (!$TESTMODE) {
# with older mountd's ls will fail,
# with newer mountd's ls will hang til mountd is done.
#
# However, mountd add exports to the kernel as it parses
# the file. So, we really have to look at the last line in
# exports and wait for that FS!
#
if ($waittildone) {
my $testdir = "/proj/" . TBOPSPID();
TBDebugTimeStampsOn();
......
......@@ -81,10 +81,11 @@ else {
$pidfile = "/var/run/mountd.pid";
$daemon = "mountd";
$exportfs = ($LINUX_FSNODE ? "/usr/sbin/exportfs -ra" : undef);
}
if (defined($opts{'i'})) {
$incremental = 1;
# incremental only applies to mountd
if (defined($opts{'i'})) {
$incremental = 1;
}
}
my $dbg = 0;
......@@ -179,6 +180,7 @@ system("mv $exportsnew $exports") == 0 or
# Avoid accidental editing.
chmod(0444, $exports);
my $checkstamp = 0;
if (!$LINUX_FSNODE) {
my $daemonpid = `cat $pidfile`;
$daemonpid =~ s/\n//;
......@@ -186,6 +188,19 @@ if (!$LINUX_FSNODE) {
if ($daemonpid =~ /^([-\@\w.]+)$/) {
$daemonpid = $1;
}
#
# Utah feature: if mountd is maintaining a timestamp file, we use
# that to determine when it has finished processing the exports.
#
# XXX since mountd always blindly updates the file, we just remove it
# here so we don't have to bother checking the content, we just have to
# wait for it to exist.
#
if (!defined($opts{'S'}) && unlink("/var/run/mountd.ts") != 0) {
$checkstamp = 1;
}
if ($incremental) {
if (kill('USR1', $daemonpid) == 0) {
fatal("Could not kill(USR1) process $daemonpid ($daemon): $!");
......@@ -210,12 +225,28 @@ else {
#
# In FreeBSD, must allow time to react since HUP'ing mountd causes all
# mounts to briefly become invalid, and this causes problems for our
# scripts (and for users). Not a problem in Linux.
# mounts to briefly become invalid. Our caller (exports_setup) checks for
# this, but we need to make sure that processing has at least started!
#
# XXX we do this on the boss-side now.
# Note that Utah has hacked mountd to write a timestamp when it is done.
# Hence we can tell exactly when it has finished. In this case, our caller
# will not wait at all.
#
#sleep(1);
if ($checkstamp) {
# On Utah Emulab with thousands of mount points, this can take 15 seconds!
my $wtime = $incremental ? 8 : 15;
for (my $i = 0; $i < $wtime; $i++) {
print "exports_setup.proxy: waiting for mountd to finish ($i)...\n";
if (-e "/var/run/mountd.ts") {
print "exports_setup.proxy: mountd done.\n";
last;
}
sleep(1);
}
} else {
sleep(1);
}
exit(0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment