autofs-5.0.1 - 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. --- 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 | 35 +++++++++++++++++++-- modules/replicated.c | 84 ++++++++++++++++++++++++++++++++------------------- 10 files changed, 128 insertions(+), 46 deletions(-) --- autofs-5.0.1.orig/daemon/automount.c +++ autofs-5.0.1/daemon/automount.c @@ -56,8 +56,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 */ @@ -1861,7 +1861,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; @@ -1902,7 +1902,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.1.orig/include/automount.h +++ autofs-5.0.1/include/automount.h @@ -441,6 +441,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.1.orig/include/replicated.h +++ autofs-5.0.1/include/replicated.h @@ -55,6 +55,7 @@ struct host { size_t addr_len; char *path; unsigned int version; + unsigned int options; unsigned int proximity; unsigned int weight; unsigned long cost; @@ -64,7 +65,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.1.orig/lib/master_parse.y +++ autofs-5.0.1/lib/master_parse.y @@ -60,8 +60,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; @@ -100,7 +101,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 @@ -183,6 +184,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; } @@ -560,6 +562,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 @@ -624,7 +627,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; @@ -810,6 +814,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.1.orig/lib/master_tok.l +++ autofs-5.0.1/lib/master_tok.l @@ -361,6 +361,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.1.orig/man/auto.master.5.in +++ autofs-5.0.1/man/auto.master.5.in @@ -154,6 +154,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.1.orig/man/autofs.5 +++ autofs-5.0.1/man/autofs.5 @@ -50,6 +50,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.1.orig/modules/mount_nfs.c +++ autofs-5.0.1/modules/mount_nfs.c @@ -64,7 +64,8 @@ int mount_mount(struct autofs_point *ap, struct host *this, *hosts = NULL; unsigned int 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 */ @@ -113,9 +114,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) @@ -136,11 +141,11 @@ int mount_mount(struct autofs_point *ap, else vers = NFS_VERS_MASK | NFS_PROTO_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.1.orig/modules/parse_sun.c +++ autofs-5.0.1/modules/parse_sun.c @@ -521,6 +521,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; @@ -567,6 +568,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; @@ -589,7 +594,7 @@ static int sun_mount(struct autofs_point if (!strcmp(fstype, "autofs") && ctxt->macros) { char *noptions = NULL; - if (!options) { + if (!options || *options == '\0') { noptions = alloca(strlen(ctxt->macros) + 1); *noptions = '\0'; } else { @@ -602,7 +607,7 @@ static int sun_mount(struct autofs_point } } - if (noptions) { + if (noptions && *noptions != '\0') { strcat(noptions, ctxt->macros); options = noptions; } else { @@ -616,7 +621,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; @@ -661,6 +666,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.1.orig/modules/replicated.c +++ autofs-5.0.1/modules/replicated.c @@ -270,7 +270,8 @@ static unsigned int get_proximity(const static struct host *new_host(const char *name, const char *addr, size_t addr_len, - unsigned int proximity, unsigned int weight) + unsigned int proximity, unsigned int weight, + unsigned int options) { struct host *new; char *tmp1, *tmp2; @@ -303,6 +304,7 @@ static struct host *new_host(const char new->addr = tmp2; new->proximity = proximity; new->weight = weight; + new->options = options; return new; } @@ -437,9 +439,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; @@ -593,7 +597,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) @@ -607,8 +614,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; @@ -635,8 +641,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); @@ -645,8 +650,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; @@ -657,10 +661,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; @@ -773,7 +778,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) @@ -788,8 +796,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; @@ -810,6 +817,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 @@ -821,8 +829,6 @@ int prune_host_list(unsigned logopt, str return 1; proximity = this->proximity; - first = this; - this = first; while (this) { struct host *next = this->next; @@ -830,8 +836,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; @@ -940,8 +945,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); @@ -958,7 +962,7 @@ int prune_host_list(unsigned logopt, str } 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 hostent he; struct hostent *phe = &he; @@ -979,15 +983,25 @@ static int add_host_addrs(struct host ** * 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(thost, sizeof(saddr.sin_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 (prx == PROXIMITY_ERROR) return 0; - if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight))) + if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight, options))) return 0; if (!add_host(list, new)) @@ -1020,16 +1034,26 @@ static int add_host_addrs(struct host ** * 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(*haddr, phe->h_length); + /* + * 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 (prx == PROXIMITY_ERROR) return 0; memcpy(&tt, *haddr, sizeof(struct in_addr)); - if (!(new = new_host(host, *haddr, phe->h_length, prx, weight))) + if (!(new = new_host(host, *haddr, phe->h_length, prx, weight, options))) return 0; if (!add_host(list, new)) { @@ -1096,7 +1120,7 @@ static int add_local_path(struct host ** } 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; @@ -1151,7 +1175,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; @@ -1173,7 +1197,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; }