Hi, Ian, list,
This patch, authored by Chris Feist, updates the replicated server code to
handle failures. Currently, if the host chosen to serve up a directory
gives a mount failure, autofs will not try the next server in the list.
This patch fixes this.
I tested this locally with the following test procedure:
Setup a replicated map in autofs pointing to two hosts.
For example:
in /etc/auto.master:
/misc2 /etc/auto.misc2
in /etc/auto.misc2:
test hosta(1):/mountpoint hostb(2):/mountpoint
Configure nfs on hosta to export /mountpoint only to 127.0.0.1 & configure
nfs on hostb to export /mountpoint to *.
You should be able to run 'ls /misc2/test' and autofs will first attempt to
mount hosta, but get permission denied, and then try to mount hostb and
succeed.
Comments welcome, as always.
-Jeff
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 7d46a86..3f9de50 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -67,6 +67,53 @@ int mount_init(void **context)
return !mount_bind;
}
+int add_bad_host(char ***badhosts_ptr, int *num_badhosts, char *badhost)
+{
+ char *newhost, *colon_loc;
+
+ debug (MODPREFIX "add_bad_host: %s", badhost);
+ (*num_badhosts)++;
+ *badhosts_ptr = realloc(*badhosts_ptr, (*num_badhosts) * sizeof(char
*));
+
+ if (*badhosts_ptr == NULL) {
+ (*num_badhosts)--;
+ return 0;
+ }
+
+
+ newhost = strdup(badhost);
+ (*badhosts_ptr)[*num_badhosts-1] = newhost;
+
+ /* Remove directory from string as we only compare hosts */
+ colon_loc = strchr(newhost, ':');
+ if (colon_loc)
+ *colon_loc = '\0';
+
+ return 1;
+}
+
+int is_bad_host(char *host, char **badhosts, int num_badhosts)
+{
+ int i;
+
+ debug(MODPREFIX "is_bad_host: %s", host);
+ for (i = 0; i < num_badhosts; i++) {
+ if (strcmp(badhosts[i], host) == 0) {
+ debug(MODPREFIX "is_bad_host: %s is bad", host);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void free_bad_hosts(char **badhosts, int num_badhosts)
+{
+ int i;
+ for (i = 0; i < num_badhosts; i++)
+ free(badhosts[i]);
+ free(badhosts);
+}
+
int is_local_addr(const char *host, const char *host_addr, int addr_len)
{
struct sockaddr_in src_addr, local_addr;
@@ -166,7 +213,8 @@ int is_local_mount(const char *hostpath)
* 1 and what = local mount path if local bind,
* else 0 and what = remote mount path
*/
-int get_best_mount(char *what, const char *original, int longtimeout)
+int get_best_mount(char *what, const char *original, int longtimeout, char
**badhosts,
+ int num_badhosts, int *is_replicated, int skiplocal)
{
char *p = what;
char *winner = NULL;
@@ -175,7 +223,6 @@ int get_best_mount(char *what, const cha
char *delim, *pstrip;
int sec = (longtimeout) ? 10 : 0;
int micros = (longtimeout) ? 0 : 100000;
- int skiplocal = longtimeout; /* clearly local is not available */
if (!p) {
*what = '\0';
@@ -189,15 +236,23 @@ int get_best_mount(char *what, const cha
if (!strchr(p, ',') && (strchr(p,':') == strrchr(p,':'))) {
int ret;
+ *is_replicated = 0;
for (pstrip = p+strlen(p) - 1; pstrip >= p; pstrip--) {
if (!isspace(*pstrip))
break;
*pstrip = '\0';
}
+ if (is_bad_host(p, badhosts, num_badhosts)) {
+ *what = '\0';
+ return 0;
+ }
+
/* Check if the host is the localhost */
ret = is_local_mount(p);
- if (ret > 0) {
+ if ((ret < 0) || (ret == 0 && skiplocal))
+ *what = '\0';
+ else if (ret > 0) {
debug(MODPREFIX "host %s: is localhost", p);
/* Strip off hostname and ':' */
@@ -208,11 +263,11 @@ int get_best_mount(char *what, const cha
what++;
}
return 1;
- } else if (ret < 0)
- *what = '\0';
+ }
return ret;
- }
+ } else
+ *is_replicated = 1;
while (p && *p) {
char *next;
@@ -237,7 +292,10 @@ int get_best_mount(char *what, const cha
*delim = '\0';
w = atoi(weight);
- alive = rpc_ping(p, sec, micros);
+ if (!is_bad_host(p, badhosts, num_badhosts))
+ alive = rpc_ping(p, sec, micros);
+ else
+ alive = 0;
if (w < winner_weight && alive) {
winner_weight = w;
winner = p;
@@ -266,6 +324,11 @@ int get_best_mount(char *what, const cha
} else
break;
+ if (is_bad_host(p, badhosts, num_badhosts)) {
+ p = next;
+ continue;
+ }
+
/* p points to a server, "next is our next parse point */
if (!skiplocal) {
/* Check if it's localhost */
@@ -336,7 +399,11 @@ int get_best_mount(char *what, const cha
/* We had more than one contender and none responded in time */
if (winner_time == 0 || winner_time > 500) {
/* We've already tried a longer timeout */
- if (!longtimeout) {
+ if (longtimeout) {
+ /* Just pick the first one. */
+ if (!is_bad_host(what, badhosts, num_badhosts))
+ winner = what;
+ } else {
/* Reset string and try again */
strcpy(what, original);
@@ -345,7 +412,9 @@ int get_best_mount(char *what, const cha
"retrying with longer timeout",
original);
- return get_best_mount(what, original, 1);
+ return get_best_mount(what, original, 1,
+ badhosts, num_badhosts,
+ is_replicated, 1);
}
}
}
@@ -394,10 +463,14 @@ int mount_mount(const char *root, const
{
char *colon, *fullpath;
char *whatstr;
+ char **badhosts = NULL;
char *nfsoptions = NULL;
int local, err;
int nosymlink = 0;
int ro = 0; /* Set if mount bind should be read-only */
+ int num_badhosts = 0;
+ int is_replicated = 1;
+ int status, existed = 1;
debug(MODPREFIX "root=%s name=%s what=%s, fstype=%s, options=%s",
root, name, what, fstype, options);
@@ -473,7 +546,8 @@ #endif
/* No colon, take this as a bind (local) entry */
local = 1;
} else if (!nosymlink) {
- local = get_best_mount(whatstr, what, 0);
+ local = get_best_mount(whatstr, what, 0, badhosts,
+ num_badhosts, &is_replicated, 0);
if (!*whatstr) {
warn(MODPREFIX "no host elected");
return 1;
@@ -494,62 +568,80 @@ #endif
if (local) {
/* Local host -- do a "bind" */
-
const char *bind_options = ro ? "ro" : "";
debug(MODPREFIX "%s is local, doing bind", name);
- return mount_bind->mount_mount(root, name, name_len,
- whatstr, "bind", bind_options,
- mount_bind->context);
- } else {
- /* Not a local host - do an NFS mount */
- int status, existed = 1;
+ if (!mount_bind->mount_mount(root, name, name_len,
+ whatstr, "bind", bind_options,
+ mount_bind->context))
+ return 0;
+ else if (!is_replicated)
+ return 1;
- debug(MODPREFIX "calling mkdir_path %s", fullpath);
+ strcpy(whatstr, what);
+ get_best_mount(whatstr, what, 0, badhosts,
+ num_badhosts, &is_replicated, 1);
+ }
- status = mkdir_path(fullpath, 0555);
- if (status && errno != EEXIST) {
- error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
- return 1;
- }
+ /* Not a local host - do an NFS mount */
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
- if (!status)
- existed = 0;
+ status = mkdir_path(fullpath, 0555);
+ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
- if (is_mounted(_PATH_MOUNTED, fullpath)) {
- error(MODPREFIX
- "warning: %s is already mounted", fullpath);
- return 0;
- }
+ if (!status)
+ existed = 0;
+
+ if (is_mounted(_PATH_MOUNTED, fullpath)) {
+ error(MODPREFIX
+ "warning: %s is already mounted", fullpath);
+ return 0;
+ }
+ do {
+ aquire_lock();
if (nfsoptions && *nfsoptions) {
debug(MODPREFIX "calling mount -t nfs " SLOPPY
" -o %s %s %s", nfsoptions, whatstr, fullpath);
err = spawnll(LOG_NOTICE,
- PATH_MOUNT, PATH_MOUNT, "-t",
- "nfs", SLOPPYOPT "-o", nfsoptions,
- whatstr, fullpath, NULL);
+ PATH_MOUNT, PATH_MOUNT, "-t",
+ "nfs", SLOPPYOPT "-o", nfsoptions,
+ whatstr, fullpath, NULL);
} else {
debug(MODPREFIX "calling mount -t nfs %s %s",
whatstr, fullpath);
err = spawnll(LOG_NOTICE,
- PATH_MOUNT, PATH_MOUNT, "-t",
- "nfs", whatstr, fullpath, NULL);
+ PATH_MOUNT, PATH_MOUNT, "-t",
+ "nfs", whatstr, fullpath, NULL);
}
+ unlink(AUTOFS_LOCK);
if (err) {
- if ((!ap.ghost && name_len) || !existed)
- rmdir_path(name);
-
- error(MODPREFIX "nfs: mount failure %s on %s",
- whatstr, fullpath);
- return 1;
- } else {
- debug(MODPREFIX "mounted %s on %s", whatstr, fullpath);
- return 0;
+ add_bad_host(&badhosts, &num_badhosts,
+ whatstr);
}
+ } while (err && strcpy(whatstr, what) && is_replicated &&
+ !get_best_mount(whatstr, what, 0, badhosts,
+ num_badhosts, &is_replicated, 1) &&
+ (*whatstr != '\0'));
+
+ free_bad_hosts(badhosts, num_badhosts);
+
+ if (err) {
+ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
+
+ error(MODPREFIX "nfs: mount failure %s on %s",
+ whatstr, fullpath);
+ return 1;
+ } else {
+ debug(MODPREFIX "mounted %s on %s", whatstr, fullpath);
+ return 0;
}
}
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs