autofs-5.0.5 - use weight only for server selection From: Ian Kent 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(-) diff --git a/CHANGELOG b/CHANGELOG index 11054da..c98204d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -55,6 +55,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 ----------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 1b1007d..6b4e0d0 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -57,8 +57,8 @@ const char *fifodir = AUTOFS_FIFO_DIR "/autofs.fifo"; 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': diff --git a/include/automount.h b/include/automount.h index 7d4efcc..5002747 100644 --- a/include/automount.h +++ b/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 */ diff --git a/include/replicated.h b/include/replicated.h index 519689d..6eb56e0 100644 --- a/include/replicated.h +++ b/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 diff --git a/lib/master_parse.y b/lib/master_parse.y index b82129f..845cbed 100644 --- a/lib/master_parse.y +++ b/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 map %type 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 { timeout = $2; } | 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 *buffer, unsigned int default_timeout, unsigne } 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; diff --git a/lib/master_tok.l b/lib/master_tok.l index d05d1fb..c7fbe37 100644 --- a/lib/master_tok.l +++ b/lib/master_tok.l @@ -363,6 +363,7 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeo -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); } diff --git a/man/auto.master.5.in b/man/auto.master.5.in index 453ff98..380b706 100644 --- a/man/auto.master.5.in +++ b/man/auto.master.5.in @@ -153,6 +153,12 @@ list of replicated servers. This option is applied to this mount 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 " Set the timeout for caching failed key lookups. This option can be used to override the global default given either on the command line diff --git a/man/autofs.5 b/man/autofs.5 index c5614e1..2161116 100644 --- a/man/autofs.5 +++ b/man/autofs.5 @@ -49,6 +49,13 @@ is used to treat errors when mounting file systems as fatal. This is important w 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 diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c index 9110eba..817b9c6 100644 --- a/modules/mount_nfs.c +++ b/modules/mount_nfs.c @@ -63,7 +63,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int 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, const char *root, const char *name, int 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, const char *root, const char *name, int 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"); diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 1f91ad1..4bddcc9 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -529,6 +529,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, { 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 *ap, const char *root, 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 *ap, const char *root, 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 *ap, const char *root, } } - if (noptions) { + if (noptions && *noptions != '\0') { strcat(noptions, ctxt->macros); options = noptions; } else { @@ -624,7 +628,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, 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 *ap, const char *root, 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", diff --git a/modules/replicated.c b/modules/replicated.c index 9eefb19..975c254 100644 --- a/modules/replicated.c +++ b/modules/replicated.c @@ -351,7 +351,8 @@ static unsigned int get_proximity(struct sockaddr *host_addr) 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 *name, new->addr = tmp2; new->proximity = proximity; new->weight = weight; + new->options = options; return new; } @@ -519,9 +521,11 @@ static unsigned short get_port_option(const char *options) 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 logopt, struct host *host, 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 logopt, struct host *host, 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 logopt, struct host *host, } 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, struct host **list, 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, struct host **list, 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, struct host **list, 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, struct host **list, 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, struct host **list, 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 **list, * 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 **list, 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 **list, } 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 **list, const char *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, struct host **hosts, } 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, struct host **hosts, *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; }