Blob Blame History Raw
autofs-5.0.5 - use weight only for server selection

From: Ian Kent <raven@themaw.net>

When using weighted server names in map entries the server response
time is also taken into consideration when selecting a server for
the target of the mount. In some cases people need to be able to
rely on selection strictly by weight. We add pseudo option
"--use-weight-only" that can be used in with master map entries
or with individual map entries to provide for this. For individual
map entries the option "no-use-weight-only" can also be used to
override the master map option.
---

 CHANGELOG            |    1 
 daemon/automount.c   |    8 ++---
 include/automount.h  |    3 ++
 include/replicated.h |    3 +-
 lib/master_parse.y   |   12 ++++++--
 lib/master_tok.l     |    1 
 man/auto.master.5.in |    6 ++++
 man/autofs.5         |    7 ++++
 modules/mount_nfs.c  |   15 ++++++----
 modules/parse_sun.c  |   36 +++++++++++++++++++++---
 modules/replicated.c |   76 ++++++++++++++++++++++++++++++---------------------
 11 files changed, 120 insertions(+), 48 deletions(-)


--- autofs-5.0.5.orig/CHANGELOG
+++ autofs-5.0.5/CHANGELOG
@@ -54,6 +54,7 @@
 - add external bind method.
 - fix add simple bind auth.
 - add option to dump configured automount maps.
+- use weight only for server selection.
 
 03/09/2009 autofs-5.0.5
 -----------------------
--- autofs-5.0.5.orig/daemon/automount.c
+++ autofs-5.0.5/daemon/automount.c
@@ -57,8 +57,8 @@ const char *fifodir = AUTOFS_FIFO_DIR "/
 const char *global_options;		/* Global option, from command line */
 
 static char *pid_file = NULL;		/* File in which to keep pid */
-unsigned int global_random_selection;	/* use random policy when selecting
-					 * which multi-mount host to mount */
+unsigned int global_selection_options;
+
 long global_negative_timeout = -1;
 int do_force_unlink = 0;		/* Forceably unlink mount tree at startup */
 
@@ -1855,7 +1855,7 @@ int main(int argc, char *argv[])
 	timeout = defaults_get_timeout();
 	ghost = defaults_get_browse_mode();
 	logging = defaults_get_logging();
-	global_random_selection = 0;
+	global_selection_options = 0;
 	global_options = NULL;
 	have_global_options = 0;
 	foreground = 0;
@@ -1898,7 +1898,7 @@ int main(int argc, char *argv[])
 			exit(0);
 
 		case 'r':
-			global_random_selection = 1;
+			global_selection_options |= MOUNT_FLAG_RANDOM_SELECT;
 			break;
 
 		case 'n':
--- autofs-5.0.5.orig/include/automount.h
+++ autofs-5.0.5/include/automount.h
@@ -443,6 +443,9 @@ struct kernel_mod_version {
 /* Mount being re-mounted */
 #define MOUNT_FLAG_REMOUNT		0x0008
 
+/* Use server weight only for selection */
+#define MOUNT_FLAG_USE_WEIGHT_ONLY	0x0010
+
 struct autofs_point {
 	pthread_t thid;
 	char *path;			/* Mount point name */
--- autofs-5.0.5.orig/include/replicated.h
+++ autofs-5.0.5/include/replicated.h
@@ -56,6 +56,7 @@ struct host {
 	size_t addr_len;
 	char *path;
 	unsigned int version;
+	unsigned int options;
 	unsigned int proximity;
 	unsigned int weight;
 	unsigned long cost;
@@ -65,7 +66,7 @@ struct host {
 void seed_random(void);
 void free_host_list(struct host **);
 int parse_location(unsigned, struct host **, const char *, unsigned int);
-int prune_host_list(unsigned, struct host **, unsigned int, const char *, unsigned int);
+int prune_host_list(unsigned, struct host **, unsigned int, const char *);
 void dump_host_list(struct host *);
 
 #endif
--- autofs-5.0.5.orig/lib/master_parse.y
+++ autofs-5.0.5/lib/master_parse.y
@@ -58,8 +58,9 @@ static char *format;
 static long timeout;
 static long negative_timeout;
 static unsigned ghost;
-extern unsigned global_random_selection;
+extern unsigned global_selection_options;
 static unsigned random_selection;
+static unsigned use_weight;
 static char **tmp_argv;
 static int tmp_argc;
 static char **local_argv;
@@ -98,7 +99,7 @@ static int master_fprintf(FILE *, char *
 %token COMMENT
 %token MAP
 %token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE
-%token OPT_DEBUG OPT_RANDOM
+%token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT
 %token COLON COMMA NL DDASH
 %type <strtype> map
 %type <strtype> options
@@ -181,6 +182,7 @@ line:
 	| PATH OPTION { master_notify($2); YYABORT; }
 	| PATH NILL { master_notify($2); YYABORT; }
 	| PATH OPT_RANDOM { master_notify($1); YYABORT; }
+	| PATH OPT_USE_WEIGHT { master_notify($1); YYABORT; }
 	| PATH OPT_DEBUG { master_notify($1); YYABORT; }
 	| PATH OPT_TIMEOUT { master_notify($1); YYABORT; }
 	| PATH OPT_GHOST { master_notify($1); YYABORT; }
@@ -558,6 +560,7 @@ daemon_option: OPT_TIMEOUT NUMBER { time
 	| OPT_VERBOSE	{ verbose = 1; }
 	| OPT_DEBUG	{ debug = 1; }
 	| OPT_RANDOM	{ random_selection = 1; }
+	| OPT_USE_WEIGHT { use_weight = 1; }
 	;
 
 mount_option: OPTION
@@ -622,7 +625,8 @@ static void local_init_vars(void)
 	timeout = -1;
 	negative_timeout = 0;
 	ghost = defaults_get_browse_mode();
-	random_selection = global_random_selection;
+	random_selection = global_selection_options & MOUNT_FLAG_RANDOM_SELECT;
+	use_weight = 0;
 	tmp_argv = NULL;
 	tmp_argc = 0;
 	local_argv = NULL;
@@ -808,6 +812,8 @@ int master_parse_entry(const char *buffe
 	}
 	if (random_selection)
 		entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT;
+	if (use_weight)
+		entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY;
 	if (negative_timeout)
 		entry->ap->negative_timeout = negative_timeout;
 
--- autofs-5.0.5.orig/lib/master_tok.l
+++ autofs-5.0.5/lib/master_tok.l
@@ -363,6 +363,7 @@ OPTNTOUT	(-n{OPTWS}|-n{OPTWS}={OPTWS}|--
 	-g|--ghost|-?browse	{ return(OPT_GHOST); }
 	-v|--verbose		{ return(OPT_VERBOSE); }
 	-d|--debug		{ return(OPT_DEBUG); }
+	-w|--use-weight-only	{ return(OPT_USE_WEIGHT); }
 	-r|--random-multimount-selection { return(OPT_RANDOM); }
 
 	{OPTWS}","{OPTWS}	{ return(COMMA); }
--- autofs-5.0.5.orig/man/auto.master.5.in
+++ autofs-5.0.5/man/auto.master.5.in
@@ -153,6 +153,12 @@ list of replicated servers. This option 
 only, overriding the global setting that may be specified on the
 command line.
 .TP
+.I "\-w, \-\-use-weight-only"
+Use only specified weights for server selection where more than one
+server is specified in the map entry. If no server weights are given
+then each available server will be tried in the order listed, within
+proximity.
+.TP
 .I "\-n, \-\-negative\-timeout <seconds>"
 Set the timeout for caching failed key lookups. This option can be
 used to override the global default given either on the command line
--- autofs-5.0.5.orig/man/autofs.5
+++ autofs-5.0.5/man/autofs.5
@@ -49,6 +49,13 @@ is used to treat errors when mounting fi
 multiple file systems should be mounted (`multi-mounts'). If this option
 is given, no file system is mounted at all if at least one file system
 can't be mounted.
+.I -use-weight-only
+is used to make the weight the sole factor in selecting a server when multiple
+servers are present in a map entry.
+and
+.I -no-use-weight-only
+can be used to negate the option if it is present in the master map entry
+for the map but is not wanted for the given mount.
 
 .SS location
 The location specifies from where the file system is to be mounted.  In the
--- autofs-5.0.5.orig/modules/mount_nfs.c
+++ autofs-5.0.5/modules/mount_nfs.c
@@ -63,7 +63,8 @@ int mount_mount(struct autofs_point *ap,
 	struct host *this, *hosts = NULL;
 	unsigned int mount_default_proto, vers;
 	char *nfsoptions = NULL;
-	unsigned int random_selection = ap->flags & MOUNT_FLAG_RANDOM_SELECT;
+	unsigned int flags = ap->flags &
+			(MOUNT_FLAG_RANDOM_SELECT | MOUNT_FLAG_USE_WEIGHT_ONLY);
 	int len, status, err, existed = 1;
 	int nosymlink = 0;
 	int ro = 0;            /* Set if mount bind should be read-only */
@@ -112,9 +113,13 @@ int mount_mount(struct autofs_point *ap,
 			while (*comma == ' ' || *comma == '\t')
 				end--;
 
-			if (strncmp("nosymlink", cp, end - cp + 1) == 0)
+			if (strncmp("nosymlink", cp, end - cp + 1) == 0) {
 				nosymlink = 1;
-			else {
+			} else if (strncmp("no-use-weight-only", cp, end - cp + 1) == 0) {
+				flags &= ~MOUNT_FLAG_USE_WEIGHT_ONLY;
+			} else if (strncmp("use-weight-only", cp, end - cp + 1) == 0) {
+				flags |= MOUNT_FLAG_USE_WEIGHT_ONLY;
+			} else {
 				/* Check for options that also make sense
 				   with bind mounts */
 				if (strncmp("ro", cp, end - cp + 1) == 0)
@@ -137,11 +142,11 @@ int mount_mount(struct autofs_point *ap,
 	else if (mount_default_proto == 4)
 		vers = vers | NFS4_VERS_MASK;
 
-	if (!parse_location(ap->logopt, &hosts, what, random_selection)) {
+	if (!parse_location(ap->logopt, &hosts, what, flags)) {
 		info(ap->logopt, MODPREFIX "no hosts available");
 		return 1;
 	}
-	prune_host_list(ap->logopt, &hosts, vers, nfsoptions, random_selection);
+	prune_host_list(ap->logopt, &hosts, vers, nfsoptions);
 
 	if (!hosts) {
 		info(ap->logopt, MODPREFIX "no hosts available");
--- autofs-5.0.5.orig/modules/parse_sun.c
+++ autofs-5.0.5/modules/parse_sun.c
@@ -529,6 +529,7 @@ static int sun_mount(struct autofs_point
 {
 	char *fstype = "nfs";	/* Default filesystem type */
 	int nonstrict = 1;
+	int use_weight_only = ap->flags & MOUNT_FLAG_USE_WEIGHT_ONLY;
 	int rv, cur_state;
 	char *mountpoint;
 	char *what;
@@ -575,6 +576,10 @@ static int sun_mount(struct autofs_point
 					memcpy(np, cp, comma - cp + 1);
 					np += comma - cp + 1;
 				}
+			} else if (strncmp("no-use-weight-only", cp, 18) == 0) {
+				use_weight_only = -1;
+			} else if (strncmp("use-weight-only", cp, 15) == 0) {
+				use_weight_only = MOUNT_FLAG_USE_WEIGHT_ONLY;
 			} else if (strncmp("bg", cp, 2) == 0 ||
 				   strncmp("nofg", cp, 4) == 0) {
 				continue;
@@ -593,11 +598,10 @@ static int sun_mount(struct autofs_point
 		options = noptions;
 	}
 
-
 	if (!strcmp(fstype, "autofs") && ctxt->macros) {
 		char *noptions = NULL;
 
-		if (!options) {
+		if (!options || *options == '\0') {
 			noptions = alloca(strlen(ctxt->macros) + 1);
 			*noptions = '\0';
 		} else {
@@ -610,7 +614,7 @@ static int sun_mount(struct autofs_point
 			}
 		}
 
-		if (noptions) {
+		if (noptions && *noptions != '\0') {
 			strcat(noptions, ctxt->macros);
 			options = noptions;
 		} else {
@@ -624,7 +628,7 @@ static int sun_mount(struct autofs_point
 
 	type = ap->entry->maps->type;
 	if (type && !strcmp(type, "hosts")) {
-		if (options) {
+		if (options && *options != '\0') {
 			int len = strlen(options);
 			int suid = strstr(options, "suid") ? 0 : 7;
 			int dev = strstr(options, "dev") ? 0 : 6;
@@ -669,6 +673,30 @@ static int sun_mount(struct autofs_point
 		memcpy(what, loc, loclen);
 		what[loclen] = '\0';
 
+		/* Add back "[no-]use-weight-only" for NFS mounts only */
+		if (use_weight_only) {
+			char *tmp;
+			int len;
+
+			if (options && *options != '\0') {
+				len = strlen(options) + 19;
+				tmp = alloca(len);
+				strcpy(tmp, options);
+				strcat(tmp, ",");
+				if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY)
+					strcat(tmp, "use-weight-only");
+				else
+					strcat(tmp, "no-use-weight-only");
+			} else {
+				tmp = alloca(19);
+				if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY)
+					strcpy(tmp, "use-weight-only");
+				else
+					strcpy(tmp, "no-use-weight-only");
+			}
+			options = tmp;
+		}
+
 		debug(ap->logopt, MODPREFIX
 		      "mounting root %s, mountpoint %s, "
 		      "what %s, fstype %s, options %s",
--- autofs-5.0.5.orig/modules/replicated.c
+++ autofs-5.0.5/modules/replicated.c
@@ -351,7 +351,8 @@ static unsigned int get_proximity(struct
 
 static struct host *new_host(const char *name,
 			     struct sockaddr *addr, size_t addr_len,
-			     unsigned int proximity, unsigned int weight)
+			     unsigned int proximity, unsigned int weight,
+			     unsigned int options)
 {
 	struct host *new;
 	struct sockaddr *tmp2;
@@ -385,6 +386,7 @@ static struct host *new_host(const char 
 	new->addr = tmp2;
 	new->proximity = proximity;
 	new->weight = weight;
+	new->options = options;
 
 	return new;
 }
@@ -519,9 +521,11 @@ static unsigned short get_port_option(co
 static unsigned int get_nfs_info(unsigned logopt, struct host *host,
 			 struct conn_info *pm_info, struct conn_info *rpc_info,
 			 const char *proto, unsigned int version,
-			 const char *options, unsigned int random_selection)
+			 const char *options)
 {
 	char *have_port_opt = options ? strstr(options, "port=") : NULL;
+	unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT;
+	unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY;
 	struct pmap parms;
 	struct timeval start, end;
 	struct timezone tz;
@@ -675,7 +679,10 @@ done_ver:
 		 * Average response time to 7 significant places as
 		 * integral type.
 		 */
-		host->cost = (unsigned long) ((taken * 1000000) / count);
+		if (use_weight_only)
+			host->cost = 1;
+		else
+			host->cost = (unsigned long) ((taken * 1000000) / count);
 
 		/* Allow for user bias */
 		if (host->weight)
@@ -689,8 +696,7 @@ done_ver:
 }
 
 static int get_vers_and_cost(unsigned logopt, struct host *host,
-			     unsigned int version, const char *options,
-			     unsigned int random_selection)
+			     unsigned int version, const char *options)
 {
 	struct conn_info pm_info, rpc_info;
 	time_t timeout = RPC_TIMEOUT;
@@ -717,8 +723,7 @@ static int get_vers_and_cost(unsigned lo
 
 	if (version & UDP_REQUESTED) {
 		supported = get_nfs_info(logopt, host,
-					&pm_info, &rpc_info, "udp", vers,
-					options, random_selection);
+				   &pm_info, &rpc_info, "udp", vers, options);
 		if (supported) {
 			ret = 1;
 			host->version |= (supported << 8);
@@ -727,8 +732,7 @@ static int get_vers_and_cost(unsigned lo
 
 	if (version & TCP_REQUESTED) {
 		supported = get_nfs_info(logopt, host,
-					 &pm_info, &rpc_info, "tcp", vers,
-					 options, random_selection);
+				   &pm_info, &rpc_info, "tcp", vers, options);
 		if (supported) {
 			ret = 1;
 			host->version |= supported;
@@ -739,10 +743,11 @@ static int get_vers_and_cost(unsigned lo
 }
 
 static int get_supported_ver_and_cost(unsigned logopt, struct host *host,
-				      unsigned int version, const char *options,
-				      unsigned int random_selection)
+				      unsigned int version, const char *options)
 {
 	char *have_port_opt = options ? strstr(options, "port=") : NULL;
+	unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT;
+	unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY;
 	struct conn_info pm_info, rpc_info;
 	struct pmap parms;
 	const char *proto;
@@ -855,7 +860,10 @@ done:
 
 	if (status) {
 		/* Response time to 7 significant places as integral type. */
-		host->cost = (unsigned long) (taken * 1000000);
+		if (use_weight_only)
+			host->cost = 1;
+		else
+			host->cost = (unsigned long) (taken * 1000000);
 
 		/* Allow for user bias */
 		if (host->weight)
@@ -870,8 +878,7 @@ done:
 }
 
 int prune_host_list(unsigned logopt, struct host **list,
-		    unsigned int vers, const char *options,
-		    unsigned int random_selection)
+		    unsigned int vers, const char *options)
 {
 	struct host *this, *last, *first;
 	struct host *new = NULL;
@@ -892,6 +899,7 @@ int prune_host_list(unsigned logopt, str
 	this = first;
 	while (this && this->proximity == PROXIMITY_LOCAL)
 		this = this->next;
+	first = this;
 
 	/*
 	 * Check for either a list containing only proximity local hosts
@@ -903,8 +911,6 @@ int prune_host_list(unsigned logopt, str
 		return 1;
 
 	proximity = this->proximity;
-	first = this;
-	this = first;
 	while (this) {
 		struct host *next = this->next;
 
@@ -912,8 +918,7 @@ int prune_host_list(unsigned logopt, str
 			break;
 
 		if (this->name) {
-			status = get_vers_and_cost(logopt, this, vers,
-						   options, random_selection);
+			status = get_vers_and_cost(logopt, this, vers, options);
 			if (!status) {
 				if (this == first) {
 					first = next;
@@ -1022,8 +1027,7 @@ int prune_host_list(unsigned logopt, str
 			add_host(&new, this);
 		} else {
 			status = get_supported_ver_and_cost(logopt, this,
-						selected_version, options,
-						random_selection);
+						selected_version, options);
 			if (status) {
 				this->version = selected_version;
 				remove_host(list, this);
@@ -1041,8 +1045,7 @@ int prune_host_list(unsigned logopt, str
 
 static int add_new_host(struct host **list,
 			const char *host, unsigned int weight,
-			struct addrinfo *host_addr,
-			unsigned int random_selection)
+			struct addrinfo *host_addr, unsigned int options)
 {
 	struct host *new;
 	unsigned int prx;
@@ -1054,10 +1057,21 @@ static int add_new_host(struct host **li
 	 * We can't use PROXIMITY_LOCAL or we won't perform an RPC ping
 	 * to remove hosts that may be down.
 	 */
-	if (random_selection)
+	if (options & MOUNT_FLAG_RANDOM_SELECT)
 		prx = PROXIMITY_SUBNET;
-	else
+	else {
 		prx = get_proximity(host_addr->ai_addr);
+		/*
+		 * If we want the weight to be the determining factor
+		 * when selecting a host then all hosts must have the
+		 * same proximity. However, if this is the local machine
+		 * it should always be used since it is certainly available.
+		 */
+		if (prx != PROXIMITY_LOCAL &&
+		   (options & MOUNT_FLAG_USE_WEIGHT_ONLY))
+			prx = PROXIMITY_SUBNET;
+	}
+
 	/*
 	 * If we tried to add an IPv6 address and we don't have IPv6
 	 * support return success in the hope of getting an IPv4
@@ -1069,7 +1083,7 @@ static int add_new_host(struct host **li
 		return 0;
 
 	addr_len = sizeof(struct sockaddr);
-	new = new_host(host, host_addr->ai_addr, addr_len, prx, weight);
+	new = new_host(host, host_addr->ai_addr, addr_len, prx, weight, options);
 	if (!new)
 		return 0;
 
@@ -1082,7 +1096,7 @@ static int add_new_host(struct host **li
 }
 
 static int add_host_addrs(struct host **list, const char *host,
-			  unsigned int weight, unsigned int random_selection)
+			  unsigned int weight, unsigned int options)
 {
 	struct addrinfo hints, *ni, *this;
 	int ret;
@@ -1098,7 +1112,7 @@ static int add_host_addrs(struct host **
 
 	this = ni;
 	while (this) {
-		ret = add_new_host(list, host, weight, this, random_selection);
+		ret = add_new_host(list, host, weight, this, options);
 		if (!ret)
 			break;
 		this = this->ai_next;
@@ -1121,7 +1135,7 @@ try_name:
 
 	this = ni;
 	while (this) {
-		ret = add_new_host(list, host, weight, this, random_selection);
+		ret = add_new_host(list, host, weight, this, options);
 		if (!ret)
 			break;
 		this = this->ai_next;
@@ -1209,7 +1223,7 @@ static char *seek_delim(const char *s)
 }
 
 int parse_location(unsigned logopt, struct host **hosts,
-		   const char *list, unsigned int random_selection)
+		   const char *list, unsigned int options)
 {
 	char *str, *p, *delim;
 	unsigned int empty = 1;
@@ -1264,7 +1278,7 @@ int parse_location(unsigned logopt, stru
 				}
 
 				if (p != delim) {
-					if (!add_host_addrs(hosts, p, weight, random_selection)) {
+					if (!add_host_addrs(hosts, p, weight, options)) {
 						if (empty) {
 							p = next;
 							continue;
@@ -1286,7 +1300,7 @@ int parse_location(unsigned logopt, stru
 				*delim = '\0';
 				next = delim + 1;
 
-				if (!add_host_addrs(hosts, p, weight, random_selection)) {
+				if (!add_host_addrs(hosts, p, weight, options)) {
 					p = next;
 					continue;
 				}