|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* repl_list.h - routines for replicated mount server selection
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved
|
|
Packit |
8480eb |
* Copyright 2004-2006 Ian Kent <raven@themaw.net> - All Rights Reserved
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8480eb |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8480eb |
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
|
Packit |
8480eb |
* USA; either version 2 of the License, or (at your option) any later
|
|
Packit |
8480eb |
* version; incorporated herein by reference.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* A priority ordered list of hosts is created by using the following
|
|
Packit |
8480eb |
* selection rules.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* 1) Highest priority in selection is proximity.
|
|
Packit |
8480eb |
* Proximity, in order of precedence is:
|
|
Packit |
8480eb |
* - PROXIMITY_LOCAL, host corresponds to a local interface.
|
|
Packit |
8480eb |
* - PROXIMITY_SUBNET, host is located in a subnet reachable
|
|
Packit |
8480eb |
* through a local interface.
|
|
Packit |
8480eb |
* - PROXIMITY_NETWORK, host is located in a network reachable
|
|
Packit |
8480eb |
* through a local interface.
|
|
Packit |
8480eb |
* - PROXIMITY_OTHER, host is on a network not directlty
|
|
Packit |
8480eb |
* reachable through a local interface.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* 2) NFS version and protocol is selected by caclculating the largest
|
|
Packit |
8480eb |
* number of hosts supporting an NFS version and protocol that
|
|
Packit |
8480eb |
* have the closest proximity. These hosts are added to the list
|
|
Packit |
8480eb |
* in response time order. Hosts may have a corresponding weight
|
|
Packit |
8480eb |
* which essentially increaes response time and so influences the
|
|
Packit |
8480eb |
* host order.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* 3) Hosts at further proximity that support the selected NFS version
|
|
Packit |
8480eb |
* and protocol are also added to the list in response time order as
|
|
Packit |
8480eb |
* in 2 above.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifndef _GNU_SOURCE
|
|
Packit |
8480eb |
#define _GNU_SOURCE
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <string.h>
|
|
Packit |
8480eb |
#include <stdlib.h>
|
|
Packit |
8480eb |
#include <sys/errno.h>
|
|
Packit |
8480eb |
#include <sys/types.h>
|
|
Packit |
8480eb |
#include <stdint.h>
|
|
Packit |
8480eb |
#include <sys/ioctl.h>
|
|
Packit |
8480eb |
#include <sys/socket.h>
|
|
Packit |
8480eb |
#include <netinet/in.h>
|
|
Packit |
8480eb |
#include <netdb.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include "rpc_subs.h"
|
|
Packit |
8480eb |
#include "replicated.h"
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifndef MAX_ERR_BUF
|
|
Packit |
8480eb |
#define MAX_ERR_BUF 512
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define mymax(x, y) (x >= y ? x : y)
|
|
Packit |
8480eb |
#define mmax(x, y, z) (mymax(x, y) == x ? mymax(x, z) : mymax(y, z))
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void seed_random(void)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
unsigned int seed;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
fd = open_fd("/dev/urandom", O_RDONLY);
|
|
Packit |
8480eb |
if (fd < 0) {
|
|
Packit |
8480eb |
srandom(monotonic_time(NULL));
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (read(fd, &seed, sizeof(seed)) != -1)
|
|
Packit |
8480eb |
srandom(seed);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
srandom(monotonic_time(NULL));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
close(fd);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
145c60 |
struct host *new_host(const char *name,
|
|
Packit |
8480eb |
struct sockaddr *addr, size_t addr_len,
|
|
Packit |
8480eb |
unsigned int proximity, unsigned int weight,
|
|
Packit |
8480eb |
unsigned int options)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *new;
|
|
Packit |
8480eb |
struct sockaddr *tmp2;
|
|
Packit |
8480eb |
char *tmp1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!name || !addr)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tmp1 = strdup(name);
|
|
Packit |
8480eb |
if (!tmp1)
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tmp2 = malloc(addr_len);
|
|
Packit |
8480eb |
if (!tmp2) {
|
|
Packit |
8480eb |
free(tmp1);
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
memcpy(tmp2, addr, addr_len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
new = malloc(sizeof(struct host));
|
|
Packit |
8480eb |
if (!new) {
|
|
Packit |
8480eb |
free(tmp1);
|
|
Packit |
8480eb |
free(tmp2);
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(new, 0, sizeof(struct host));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
new->name = tmp1;
|
|
Packit |
8480eb |
new->addr_len = addr_len;
|
|
Packit |
8480eb |
new->addr = tmp2;
|
|
Packit |
8480eb |
new->proximity = proximity;
|
|
Packit |
8480eb |
new->weight = weight;
|
|
Packit |
8480eb |
new->options = options;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return new;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int add_host(struct host **list, struct host *host)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *this, *last;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!*list) {
|
|
Packit |
8480eb |
*list = host;
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = *list;
|
|
Packit |
8480eb |
last = this;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
if (this->proximity >= host->proximity)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
last = this;
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host->cost) {
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
if (this->proximity != host->proximity)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
if (this->cost >= host->cost)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
last = this;
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (last == this) {
|
|
Packit |
8480eb |
host->next = last;
|
|
Packit |
8480eb |
*list = host;
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
last->next = host;
|
|
Packit |
8480eb |
host->next = this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void free_host(struct host *host)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
free(host->name);
|
|
Packit |
8480eb |
free(host->addr);
|
|
Packit |
8480eb |
free(host->path);
|
|
Packit |
8480eb |
free(host);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void remove_host(struct host **hosts, struct host *host)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *last, *this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host == *hosts) {
|
|
Packit |
8480eb |
*hosts = (*hosts)->next;
|
|
Packit |
8480eb |
host->next = NULL;
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = *hosts;
|
|
Packit |
8480eb |
last = NULL;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
if (this == host)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
last = this;
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!last || !this)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
last->next = this->next;
|
|
Packit |
8480eb |
host->next = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void delete_host(struct host **hosts, struct host *host)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
remove_host(hosts, host);
|
|
Packit |
8480eb |
free_host(host);
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void free_host_list(struct host **list)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = *list;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
struct host *next = this->next;
|
|
Packit |
8480eb |
free_host(this);
|
|
Packit |
8480eb |
this = next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
*list = NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static unsigned int get_nfs_info(unsigned logopt, struct host *host,
|
|
Packit |
8480eb |
struct conn_info *pm_info, struct conn_info *rpc_info,
|
|
Packit |
8480eb |
int proto, unsigned int version, int port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT;
|
|
Packit |
8480eb |
unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY;
|
|
Packit |
8480eb |
socklen_t len = INET6_ADDRSTRLEN;
|
|
Packit |
8480eb |
char buf[len + 1];
|
|
Packit |
8480eb |
struct pmap parms;
|
|
Packit |
8480eb |
struct timespec start, end;
|
|
Packit |
8480eb |
unsigned int supported = 0;
|
|
Packit |
8480eb |
double taken = 0;
|
|
Packit |
8480eb |
int status, count = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host->addr)
|
|
Packit |
8480eb |
debug(logopt, "called with host %s(%s) proto %d version 0x%x",
|
|
Packit |
8480eb |
host->name, get_addr_string(host->addr, buf, len),
|
|
Packit |
8480eb |
proto, version);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"called for host %s proto %d version 0x%x",
|
|
Packit |
8480eb |
host->name, proto, version);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
rpc_info->proto = proto;
|
|
Packit |
8480eb |
if (port < 0) {
|
|
Packit |
8480eb |
if (version & NFS4_REQUESTED)
|
|
Packit |
8480eb |
rpc_info->port = NFS_PORT;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
port = 0;
|
|
Packit |
8480eb |
} else if (port > 0)
|
|
Packit |
8480eb |
rpc_info->port = port;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&parms, 0, sizeof(struct pmap));
|
|
Packit |
8480eb |
parms.pm_prog = NFS_PROGRAM;
|
|
Packit |
8480eb |
parms.pm_prot = proto;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!(version & NFS4_REQUESTED))
|
|
Packit |
8480eb |
goto v3_ver;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!port) {
|
|
Packit |
8480eb |
status = rpc_portmap_getclient(pm_info,
|
|
Packit |
8480eb |
host->name, host->addr, host->addr_len,
|
|
Packit |
8480eb |
proto, RPC_CLOSE_DEFAULT);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable getting portmap client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status) {
|
|
Packit |
8480eb |
debug(logopt, "error 0x%d getting portmap client");
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
parms.pm_vers = NFS4_VERSION;
|
|
Packit |
8480eb |
status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable or timed out getting service port");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status < 0) {
|
|
Packit |
8480eb |
if (version & NFS_VERS_MASK)
|
|
Packit |
8480eb |
goto v3_ver; /* MOUNT_NFS_DEFAULT_PROTOCOL=4 */
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"error 0x%d getting service port");
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (rpc_info->proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt, "host not reachable getting RPC client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (!status) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &start;;
|
|
Packit |
8480eb |
status = rpc_ping_proto(rpc_info);
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &end;;
|
|
Packit |
8480eb |
if (status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt, "host NFS ping timed out");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status > 0) {
|
|
Packit |
8480eb |
double reply;
|
|
Packit |
8480eb |
if (random_selection) {
|
|
Packit |
8480eb |
/* Random value between 0 and 1 */
|
|
Packit |
8480eb |
reply = ((float) random())/((float) RAND_MAX+1);
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"nfs v4 random selection time: %f", reply);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
reply = monotonic_elapsed(start, end);
|
|
Packit |
8480eb |
debug(logopt, "nfs v4 rpc ping time: %f", reply);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
taken += reply;
|
|
Packit |
8480eb |
count++;
|
|
Packit |
8480eb |
supported = NFS4_SUPPORTED;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!(version & NFS_VERS_MASK))
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
v3_ver:
|
|
Packit |
8480eb |
if (!(version & NFS3_REQUESTED))
|
|
Packit |
8480eb |
goto v2_ver;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!port && !pm_info->client) {
|
|
Packit |
8480eb |
status = rpc_portmap_getclient(pm_info,
|
|
Packit |
8480eb |
host->name, host->addr, host->addr_len,
|
|
Packit |
8480eb |
proto, RPC_CLOSE_DEFAULT);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable getting portmap client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"error 0x%d getting getting portmap client");
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!port) {
|
|
Packit |
8480eb |
parms.pm_vers = NFS3_VERSION;
|
|
Packit |
8480eb |
status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable or timed out getting service port");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status < 0)
|
|
Packit |
8480eb |
goto v2_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (rpc_info->proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt, "host not reachable getting RPC client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (!status) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &start;;
|
|
Packit |
8480eb |
status = rpc_ping_proto(rpc_info);
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &end;;
|
|
Packit |
8480eb |
if (status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt, "host NFS ping timed out");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status > 0) {
|
|
Packit |
8480eb |
double reply;
|
|
Packit |
8480eb |
if (random_selection) {
|
|
Packit |
8480eb |
/* Random value between 0 and 1 */
|
|
Packit |
8480eb |
reply = ((float) random())/((float) RAND_MAX+1);
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"nfs v3 random selection time: %f", reply);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
reply = monotonic_elapsed(start, end);
|
|
Packit |
8480eb |
debug(logopt, "nfs v3 rpc ping time: %f", reply);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
taken += reply;
|
|
Packit |
8480eb |
count++;
|
|
Packit |
8480eb |
supported |= NFS3_SUPPORTED;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
v2_ver:
|
|
Packit |
8480eb |
if (!(version & NFS2_REQUESTED))
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!port && !pm_info->client) {
|
|
Packit |
8480eb |
status = rpc_portmap_getclient(pm_info,
|
|
Packit |
8480eb |
host->name, host->addr, host->addr_len,
|
|
Packit |
8480eb |
proto, RPC_CLOSE_DEFAULT);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable getting portmap client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status)
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!port) {
|
|
Packit |
8480eb |
parms.pm_vers = NFS2_VERSION;
|
|
Packit |
8480eb |
status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"host not reachable or timed out getting service port");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (status < 0)
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (rpc_info->proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
debug(logopt, "host not reachable getting RPC client");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
goto done_ver;
|
|
Packit |
8480eb |
} else if (!status) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &start;;
|
|
Packit |
8480eb |
status = rpc_ping_proto(rpc_info);
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &end;;
|
|
Packit |
8480eb |
if (status == -ETIMEDOUT) {
|
|
Packit |
8480eb |
debug(logopt, "host NFS ping timed out");
|
|
Packit |
8480eb |
supported = status;
|
|
Packit |
8480eb |
} else if (status > 0) {
|
|
Packit |
8480eb |
double reply;
|
|
Packit |
8480eb |
if (random_selection) {
|
|
Packit |
8480eb |
/* Random value between 0 and 1 */
|
|
Packit |
8480eb |
reply = ((float) random())/((float) RAND_MAX+1);
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"nfs v2 random selection time: %f", reply);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
reply = monotonic_elapsed(start, end);;
|
|
Packit |
8480eb |
debug(logopt, "nfs v2 rpc ping time: %f", reply);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
taken += reply;
|
|
Packit |
8480eb |
count++;
|
|
Packit |
8480eb |
supported |= NFS2_SUPPORTED;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
done_ver:
|
|
Packit |
8480eb |
if (rpc_info->proto == IPPROTO_UDP) {
|
|
Packit |
8480eb |
rpc_destroy_udp_client(rpc_info);
|
|
Packit |
8480eb |
rpc_destroy_udp_client(pm_info);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
rpc_destroy_tcp_client(rpc_info);
|
|
Packit |
8480eb |
rpc_destroy_tcp_client(pm_info);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (count) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Average response time to 7 significant places as
|
|
Packit |
8480eb |
* integral type.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (use_weight_only)
|
|
Packit |
8480eb |
host->cost = 1;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
host->cost = (unsigned long) ((taken * 1000000) / count);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Allow for user bias */
|
|
Packit |
8480eb |
if (host->weight)
|
|
Packit |
8480eb |
host->cost *= (host->weight + 1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(logopt, "host %s cost %ld weight %d",
|
|
Packit |
8480eb |
host->name, host->cost, host->weight);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return supported;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int check_address_proto(unsigned logopt,
|
|
Packit |
8480eb |
struct host *host, unsigned int version)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int ipv6_requested = version & (TCP6_REQUESTED | UDP6_REQUESTED);
|
|
Packit |
8480eb |
int ret = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If a protocol has been explicitly requested then don't
|
|
Packit |
8480eb |
* consider addresses that don't match the requested protocol.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (ipv6_requested) {
|
|
Packit |
8480eb |
if (host->addr_len == INET_ADDRSTRLEN)
|
|
Packit |
8480eb |
ret = 0;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
if (host->addr_len == INET6_ADDRSTRLEN)
|
|
Packit |
8480eb |
ret = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!ret)
|
|
Packit |
8480eb |
debug(logopt, "requested protocol does not match address");
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int get_vers_and_cost(unsigned logopt, struct host *host,
|
|
Packit |
8480eb |
unsigned int version, int port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct conn_info pm_info, rpc_info;
|
|
Packit |
8480eb |
time_t timeout = RPC_TIMEOUT;
|
|
Packit |
8480eb |
unsigned int supported, vers = (NFS_VERS_MASK | NFS4_VERS_MASK);
|
|
Packit |
8480eb |
int ret = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!check_address_proto(logopt, host, version))
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&pm_info, 0, sizeof(struct conn_info));
|
|
Packit |
8480eb |
memset(&rpc_info, 0, sizeof(struct conn_info));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host->proximity == PROXIMITY_NET)
|
|
Packit |
8480eb |
timeout = RPC_TIMEOUT * 2;
|
|
Packit |
8480eb |
else if (host->proximity == PROXIMITY_OTHER)
|
|
Packit |
8480eb |
timeout = RPC_TIMEOUT * 8;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
rpc_info.host = host->name;
|
|
Packit |
8480eb |
rpc_info.addr = host->addr;
|
|
Packit |
8480eb |
rpc_info.addr_len = host->addr_len;
|
|
Packit |
8480eb |
rpc_info.program = NFS_PROGRAM;
|
|
Packit |
8480eb |
rpc_info.timeout.tv_sec = timeout;
|
|
Packit |
8480eb |
rpc_info.close_option = RPC_CLOSE_DEFAULT;
|
|
Packit |
8480eb |
rpc_info.client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
vers &= version;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (version & TCP_REQUESTED) {
|
|
Packit |
8480eb |
supported = get_nfs_info(logopt, host,
|
|
Packit |
8480eb |
&pm_info, &rpc_info, IPPROTO_TCP, vers, port);
|
|
Packit |
8480eb |
if (IS_ERR(supported)) {
|
|
Packit |
8480eb |
if (ERR(supported) == EHOSTUNREACH ||
|
|
Packit |
8480eb |
ERR(supported) == ETIMEDOUT)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
} else if (supported) {
|
|
Packit |
8480eb |
ret = 1;
|
|
Packit |
8480eb |
host->version |= supported;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (version & UDP_REQUESTED) {
|
|
Packit |
8480eb |
supported = get_nfs_info(logopt, host,
|
|
Packit |
8480eb |
&pm_info, &rpc_info, IPPROTO_UDP, vers, port);
|
|
Packit |
8480eb |
if (IS_ERR(supported)) {
|
|
Packit |
8480eb |
if (!ret && ERR(supported) == ETIMEDOUT)
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
} else if (supported) {
|
|
Packit |
8480eb |
ret = 1;
|
|
Packit |
8480eb |
host->version |= (supported << 8);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int get_supported_ver_and_cost(unsigned logopt, struct host *host,
|
|
Packit |
8480eb |
unsigned int version, int port)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT;
|
|
Packit |
8480eb |
unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY;
|
|
Packit |
8480eb |
socklen_t len = INET6_ADDRSTRLEN;
|
|
Packit |
8480eb |
char buf[len + 1];
|
|
Packit |
8480eb |
struct conn_info pm_info, rpc_info;
|
|
Packit |
8480eb |
int proto;
|
|
Packit |
8480eb |
unsigned int vers;
|
|
Packit |
8480eb |
struct timespec start, end;
|
|
Packit |
8480eb |
double taken = 0;
|
|
Packit |
8480eb |
time_t timeout = RPC_TIMEOUT;
|
|
Packit |
8480eb |
int status = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host->addr)
|
|
Packit |
8480eb |
debug(logopt, "called with host %s(%s) version 0x%x",
|
|
Packit |
8480eb |
host->name, get_addr_string(host->addr, buf, len),
|
|
Packit |
8480eb |
version);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
debug(logopt, "called with host %s version 0x%x",
|
|
Packit |
8480eb |
host->name, version);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!check_address_proto(logopt, host, version))
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&pm_info, 0, sizeof(struct conn_info));
|
|
Packit |
8480eb |
memset(&rpc_info, 0, sizeof(struct conn_info));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host->proximity == PROXIMITY_NET)
|
|
Packit |
8480eb |
timeout = RPC_TIMEOUT * 2;
|
|
Packit |
8480eb |
else if (host->proximity == PROXIMITY_OTHER)
|
|
Packit |
8480eb |
timeout = RPC_TIMEOUT * 8;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
rpc_info.host = host->name;
|
|
Packit |
8480eb |
rpc_info.addr = host->addr;
|
|
Packit |
8480eb |
rpc_info.addr_len = host->addr_len;
|
|
Packit |
8480eb |
rpc_info.program = NFS_PROGRAM;
|
|
Packit |
8480eb |
rpc_info.timeout.tv_sec = timeout;
|
|
Packit |
8480eb |
rpc_info.close_option = RPC_CLOSE_DEFAULT;
|
|
Packit |
8480eb |
rpc_info.client = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* The version passed in is the version as defined in
|
|
Packit |
8480eb |
* include/replicated.h. However, the version we want to send
|
|
Packit |
8480eb |
* off to the rpc calls should match the program version of NFS.
|
|
Packit |
8480eb |
* So, we do the conversion here.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (version & UDP_SELECTED_MASK) {
|
|
Packit |
8480eb |
proto = IPPROTO_UDP;
|
|
Packit |
8480eb |
version >>= 8;
|
|
Packit |
8480eb |
} else
|
|
Packit |
8480eb |
proto = IPPROTO_TCP;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
switch (version) {
|
|
Packit |
8480eb |
case NFS2_SUPPORTED:
|
|
Packit |
8480eb |
vers = NFS2_VERSION;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case NFS3_SUPPORTED:
|
|
Packit |
8480eb |
vers = NFS3_VERSION;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
case NFS4_SUPPORTED:
|
|
Packit |
8480eb |
vers = NFS4_VERSION;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
default:
|
|
Packit |
8480eb |
crit(logopt, "called with invalid version: 0x%x\n", version);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
rpc_info.proto = proto;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (port > 0)
|
|
Packit |
8480eb |
rpc_info.port = port;
|
|
Packit |
8480eb |
else if (vers & NFS4_VERSION && port < 0)
|
|
Packit |
8480eb |
rpc_info.port = NFS_PORT;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
struct pmap parms;
|
|
Packit |
8480eb |
int ret = rpc_portmap_getclient(&pm_info,
|
|
Packit |
8480eb |
host->name, host->addr, host->addr_len,
|
|
Packit |
8480eb |
proto, RPC_CLOSE_DEFAULT);
|
|
Packit |
8480eb |
if (ret) {
|
|
Packit |
8480eb |
debug(logopt, "failed to get portmap client");
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&parms, 0, sizeof(struct pmap));
|
|
Packit |
8480eb |
parms.pm_prog = NFS_PROGRAM;
|
|
Packit |
8480eb |
parms.pm_prot = rpc_info.proto;
|
|
Packit |
8480eb |
parms.pm_vers = vers;
|
|
Packit |
8480eb |
ret = rpc_portmap_getport(&pm_info, &parms, &rpc_info.port);
|
|
Packit |
8480eb |
if (ret < 0) {
|
|
Packit |
8480eb |
debug(logopt, "failed to get service port");
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (rpc_info.proto == IPPROTO_UDP)
|
|
Packit |
8480eb |
status = rpc_udp_getclient(&rpc_info, NFS_PROGRAM, vers);
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
status = rpc_tcp_getclient(&rpc_info, NFS_PROGRAM, vers);
|
|
Packit |
8480eb |
if (status == -EHOSTUNREACH) {
|
|
Packit |
8480eb |
status = 0;
|
|
Packit |
8480eb |
debug(logopt, "host not reachable getting RPC client");
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
} else if (!status) {
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &start;;
|
|
Packit |
8480eb |
status = rpc_ping_proto(&rpc_info);
|
|
Packit |
8480eb |
clock_gettime(CLOCK_MONOTONIC, &end;;
|
|
Packit |
8480eb |
if (status > 0) {
|
|
Packit |
8480eb |
if (random_selection) {
|
|
Packit |
8480eb |
/* Random value between 0 and 1 */
|
|
Packit |
8480eb |
taken = ((float) random())/((float) RAND_MAX+1);
|
|
Packit |
8480eb |
debug(logopt, "random selection time %f", taken);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
taken = monotonic_elapsed(start, end);
|
|
Packit |
8480eb |
debug(logopt, "rpc ping time %f", taken);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
if (rpc_info.proto == IPPROTO_UDP) {
|
|
Packit |
8480eb |
rpc_destroy_udp_client(&rpc_info);
|
|
Packit |
8480eb |
rpc_destroy_udp_client(&pm_info);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
rpc_destroy_tcp_client(&rpc_info);
|
|
Packit |
8480eb |
rpc_destroy_tcp_client(&pm_info);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
/* Response time to 7 significant places as integral type. */
|
|
Packit |
8480eb |
if (use_weight_only)
|
|
Packit |
8480eb |
host->cost = 1;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
host->cost = (unsigned long) (taken * 1000000);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Allow for user bias */
|
|
Packit |
8480eb |
if (host->weight)
|
|
Packit |
8480eb |
host->cost *= (host->weight + 1);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(logopt, "cost %ld weight %d", host->cost, host->weight);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int prune_host_list(unsigned logopt, struct host **list,
|
|
Packit |
8480eb |
unsigned int vers, int port)
|
|
Packit |
8480eb |
{
|
|
Packit Service |
145c60 |
struct host *this, *last, *first;
|
|
Packit |
8480eb |
struct host *new = NULL;
|
|
Packit |
8480eb |
unsigned int proximity, selected_version = 0;
|
|
Packit |
8480eb |
unsigned int v2_tcp_count, v3_tcp_count, v4_tcp_count;
|
|
Packit |
8480eb |
unsigned int v2_udp_count, v3_udp_count, v4_udp_count;
|
|
Packit |
8480eb |
unsigned int max_udp_count, max_tcp_count, max_count;
|
|
Packit |
8480eb |
int status;
|
|
Packit |
8480eb |
int kern_vers;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!*list)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit Service |
145c60 |
/* If we're using the host name then there's no point probing
|
|
Packit Service |
145c60 |
* avialability and respose time.
|
|
Packit Service |
145c60 |
*/
|
|
Packit Service |
145c60 |
if (defaults_use_hostname_for_mounts())
|
|
Packit Service |
145c60 |
return 1;
|
|
Packit Service |
145c60 |
|
|
Packit |
8480eb |
/* Use closest hosts to choose NFS version */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
first = *list;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Get proximity of first entry after local entries */
|
|
Packit |
8480eb |
this = first;
|
|
Packit |
8480eb |
while (this && this->proximity == PROXIMITY_LOCAL)
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
first = this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Check for either a list containing only proximity local hosts
|
|
Packit |
8480eb |
* or a single host entry whose proximity isn't local. If so
|
|
Packit |
8480eb |
* return immediately as we don't want to add probe latency for
|
|
Packit |
8480eb |
* the common case of a single filesystem mount request.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* But, if the kernel understands text nfs mount options then
|
|
Packit |
8480eb |
* mount.nfs most likely bypasses its probing and lets the kernel
|
|
Packit |
8480eb |
* do all the work. This can lead to long timeouts for hosts that
|
|
Packit |
8480eb |
* are not available so check the kernel version and mount.nfs
|
|
Packit |
8480eb |
* version and probe singleton mounts if the kernel version is
|
|
Packit |
8480eb |
* greater than 2.6.22 and mount.nfs version is greater than 1.1.1.
|
|
Packit |
8480eb |
* But also allow the MOUNT_WAIT configuration parameter to override
|
|
Packit |
8480eb |
* the probing.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (nfs_mount_uses_string_options &&
|
|
Packit |
8480eb |
defaults_get_mount_wait() == -1 &&
|
|
Packit |
8480eb |
(kern_vers = linux_version_code()) > KERNEL_VERSION(2, 6, 22)) {
|
|
Packit |
8480eb |
if (!this)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
if (!this || !this->next)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
proximity = this->proximity;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
struct host *next = this->next;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->proximity != proximity)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->name) {
|
|
Packit |
8480eb |
status = get_vers_and_cost(logopt, this, vers, port);
|
|
Packit |
8480eb |
if (!status) {
|
|
Packit |
8480eb |
if (this == first) {
|
|
Packit |
8480eb |
first = next;
|
|
Packit |
8480eb |
if (next)
|
|
Packit |
8480eb |
proximity = next->proximity;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
delete_host(list, this);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
this = next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* The list of hosts that aren't proximity local may now
|
|
Packit |
8480eb |
* be empty if we haven't been able probe any so we need
|
|
Packit |
8480eb |
* to check again for a list containing only proximity
|
|
Packit |
8480eb |
* local hosts.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!first)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
last = this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Select NFS version of highest number of closest servers */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
v4_tcp_count = v3_tcp_count = v2_tcp_count = 0;
|
|
Packit |
8480eb |
v4_udp_count = v3_udp_count = v2_udp_count = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = first;
|
|
Packit |
8480eb |
do {
|
|
Packit |
8480eb |
if (this->version & NFS4_TCP_SUPPORTED)
|
|
Packit |
8480eb |
v4_tcp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->version & NFS3_TCP_SUPPORTED)
|
|
Packit |
8480eb |
v3_tcp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->version & NFS2_TCP_SUPPORTED)
|
|
Packit |
8480eb |
v2_tcp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->version & NFS4_UDP_SUPPORTED)
|
|
Packit |
8480eb |
v4_udp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->version & NFS3_UDP_SUPPORTED)
|
|
Packit |
8480eb |
v3_udp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (this->version & NFS2_UDP_SUPPORTED)
|
|
Packit |
8480eb |
v2_udp_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
} while (this && this != last);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
max_tcp_count = mmax(v4_tcp_count, v3_tcp_count, v2_tcp_count);
|
|
Packit |
8480eb |
max_udp_count = mmax(v4_udp_count, v3_udp_count, v2_udp_count);
|
|
Packit |
8480eb |
max_count = mymax(max_tcp_count, max_udp_count);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (max_count == v4_tcp_count) {
|
|
Packit |
8480eb |
selected_version = NFS4_TCP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS4 over TCP");
|
|
Packit |
8480eb |
} else if (max_count == v3_tcp_count) {
|
|
Packit |
8480eb |
selected_version = NFS3_TCP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS3 over TCP");
|
|
Packit |
8480eb |
} else if (max_count == v2_tcp_count) {
|
|
Packit |
8480eb |
selected_version = NFS2_TCP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS2 over TCP");
|
|
Packit |
8480eb |
} else if (max_count == v4_udp_count) {
|
|
Packit |
8480eb |
selected_version = NFS4_UDP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS4 over UDP");
|
|
Packit |
8480eb |
} else if (max_count == v3_udp_count) {
|
|
Packit |
8480eb |
selected_version = NFS3_UDP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS3 over UDP");
|
|
Packit |
8480eb |
} else if (max_count == v2_udp_count) {
|
|
Packit |
8480eb |
selected_version = NFS2_UDP_SUPPORTED;
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"selected subset of hosts that support NFS2 over UDP");
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Add local and hosts with selected version to new list */
|
|
Packit |
8480eb |
this = *list;
|
|
Packit |
8480eb |
do {
|
|
Packit |
8480eb |
struct host *next = this->next;
|
|
Packit |
8480eb |
if (this->version & selected_version ||
|
|
Packit |
8480eb |
this->proximity == PROXIMITY_LOCAL) {
|
|
Packit |
8480eb |
this->version = selected_version;
|
|
Packit |
8480eb |
remove_host(list, this);
|
|
Packit |
8480eb |
add_host(&new, this);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
this = next;
|
|
Packit |
8480eb |
} while (this && this != last);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Now go through rest of list and check for chosen version
|
|
Packit |
8480eb |
* and add to new list if selected version is supported.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
first = last;
|
|
Packit |
8480eb |
this = first;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
struct host *next = this->next;
|
|
Packit |
8480eb |
if (!this->name) {
|
|
Packit |
8480eb |
remove_host(list, this);
|
|
Packit |
8480eb |
add_host(&new, this);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
status = get_supported_ver_and_cost(logopt, this,
|
|
Packit |
8480eb |
selected_version, port);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
this->version = selected_version;
|
|
Packit |
8480eb |
remove_host(list, this);
|
|
Packit |
8480eb |
add_host(&new, this);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
this = next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free_host_list(list);
|
|
Packit |
8480eb |
*list = new;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int add_new_host(struct host **list,
|
|
Packit Service |
145c60 |
const char *host, unsigned int weight,
|
|
Packit |
8480eb |
struct addrinfo *host_addr,
|
|
Packit |
8480eb |
unsigned int rr, unsigned int options)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *new;
|
|
Packit |
8480eb |
unsigned int prx;
|
|
Packit |
8480eb |
int addr_len;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
prx = get_proximity(host_addr->ai_addr);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If we want the weight to be the determining factor
|
|
Packit |
8480eb |
* when selecting a host, or we are using random selection,
|
|
Packit |
8480eb |
* then all hosts must have the same proximity. However,
|
|
Packit |
8480eb |
* if this is the local machine it should always be used
|
|
Packit |
8480eb |
* since it is certainly available.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (prx != PROXIMITY_LOCAL &&
|
|
Packit |
8480eb |
(options & (MOUNT_FLAG_USE_WEIGHT_ONLY |
|
|
Packit |
8480eb |
MOUNT_FLAG_RANDOM_SELECT)))
|
|
Packit |
8480eb |
prx = PROXIMITY_SUBNET;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If we tried to add an IPv6 address and we don't have IPv6
|
|
Packit |
8480eb |
* support return success in the hope of getting an IPv4
|
|
Packit |
8480eb |
* address later.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (prx == PROXIMITY_UNSUPPORTED)
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
if (prx == PROXIMITY_ERROR)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (host_addr->ai_addr->sa_family == AF_INET)
|
|
Packit |
8480eb |
addr_len = INET_ADDRSTRLEN;
|
|
Packit |
8480eb |
else if (host_addr->ai_addr->sa_family == AF_INET6)
|
|
Packit |
8480eb |
addr_len = INET6_ADDRSTRLEN;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit Service |
145c60 |
new = new_host(host, host_addr->ai_addr, addr_len, prx, weight, options);
|
|
Packit |
8480eb |
if (!new)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!add_host(list, new)) {
|
|
Packit |
8480eb |
free_host(new);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
new->rr = rr;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
145c60 |
static int add_host_addrs(struct host **list, const char *host,
|
|
Packit |
8480eb |
unsigned int weight, unsigned int options)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct addrinfo hints, *ni, *this;
|
|
Packit |
8480eb |
char *n_ptr;
|
|
Packit |
8480eb |
char *name = n_ptr = strdup(host);
|
|
Packit |
8480eb |
int len;
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
int rr = 0, rr4 = 0, rr6 = 0;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!name) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
error(LOGOPT_ANY, "strdup: %s", estr);
|
|
Packit |
8480eb |
error(LOGOPT_ANY, "failed to add host %s", host);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
len = strlen(name);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (name[0] == '[' && name[--len] == ']') {
|
|
Packit |
8480eb |
name[len] = '\0';
|
|
Packit |
8480eb |
name++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(&hints, 0, sizeof(hints));
|
|
Packit |
8480eb |
hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME;
|
|
Packit |
8480eb |
hints.ai_family = AF_UNSPEC;
|
|
Packit |
8480eb |
hints.ai_socktype = SOCK_DGRAM;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = getaddrinfo(name, NULL, &hints, &ni);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
goto try_name;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = ni;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit Service |
145c60 |
ret = add_new_host(list, host, weight, this, 0, options);
|
|
Packit |
8480eb |
if (!ret)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
this = this->ai_next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
freeaddrinfo(ni);
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
try_name:
|
|
Packit |
8480eb |
memset(&hints, 0, sizeof(hints));
|
|
Packit |
8480eb |
hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
|
|
Packit |
8480eb |
hints.ai_family = AF_UNSPEC;
|
|
Packit |
8480eb |
hints.ai_socktype = SOCK_DGRAM;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = getaddrinfo(name, NULL, &hints, &ni);
|
|
Packit |
8480eb |
if (ret) {
|
|
Packit Service |
145c60 |
error(LOGOPT_ANY, "hostname lookup failed: %s",
|
|
Packit Service |
145c60 |
gai_strerror(ret));
|
|
Packit |
8480eb |
free(name);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = ni;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
if (this->ai_family == AF_INET) {
|
|
Packit |
8480eb |
struct sockaddr_in *addr = (struct sockaddr_in *) this->ai_addr;
|
|
Packit |
8480eb |
if (addr->sin_addr.s_addr != INADDR_LOOPBACK)
|
|
Packit |
8480eb |
rr4++;
|
|
Packit |
8480eb |
} else if (this->ai_family == AF_INET6) {
|
|
Packit |
8480eb |
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) this->ai_addr;
|
|
Packit |
8480eb |
if (!IN6_IS_ADDR_LOOPBACK(addr->sin6_addr.s6_addr32))
|
|
Packit |
8480eb |
rr6++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
this = this->ai_next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (rr4 > 1 || rr6 > 1)
|
|
Packit |
8480eb |
rr++;
|
|
Packit |
8480eb |
this = ni;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit Service |
145c60 |
ret = add_new_host(list, host, weight, this, rr, options);
|
|
Packit |
8480eb |
if (!ret)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
this = this->ai_next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
freeaddrinfo(ni);
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
free(n_ptr);
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int add_path(struct host *hosts, const char *path, int len)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *this;
|
|
Packit |
8480eb |
char *tmp, *tmp2;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tmp = alloca(len + 1);
|
|
Packit |
8480eb |
if (!tmp)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
strncpy(tmp, path, len);
|
|
Packit |
8480eb |
tmp[len] = '\0';
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = hosts;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
if (!this->path) {
|
|
Packit |
8480eb |
tmp2 = strdup(tmp);
|
|
Packit |
8480eb |
if (!tmp2)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
this->path = tmp2;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int add_local_path(struct host **hosts, const char *path)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *new;
|
|
Packit |
8480eb |
char *tmp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tmp = strdup(path);
|
|
Packit |
8480eb |
if (!tmp)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
new = malloc(sizeof(struct host));
|
|
Packit |
8480eb |
if (!new) {
|
|
Packit |
8480eb |
free(tmp);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(new, 0, sizeof(struct host));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
new->path = tmp;
|
|
Packit |
8480eb |
new->proximity = PROXIMITY_LOCAL;
|
|
Packit |
8480eb |
new->version = NFS_VERS_MASK;
|
|
Packit |
8480eb |
new->name = NULL;
|
|
Packit |
8480eb |
new->addr = NULL;
|
|
Packit |
8480eb |
new->weight = new->cost = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
add_host(hosts, new);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static char *seek_delim(const char *s)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
const char *p = s;
|
|
Packit |
8480eb |
char *delim;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
delim = strpbrk(p, "(, \t:");
|
|
Packit |
8480eb |
if (delim && *delim != ':' && (delim == s || *(delim - 1) != '\\'))
|
|
Packit |
8480eb |
return delim;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (*p) {
|
|
Packit |
8480eb |
if (*p != ':') {
|
|
Packit |
8480eb |
p++;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (!strncmp(p, ":/", 2))
|
|
Packit |
8480eb |
return (char *) p;
|
|
Packit |
8480eb |
p++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int parse_location(unsigned logopt, struct host **hosts,
|
|
Packit |
8480eb |
const char *list, unsigned int options)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *str, *p, *delim;
|
|
Packit |
8480eb |
unsigned int empty = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!list)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
str = strdup(list);
|
|
Packit |
8480eb |
if (!str)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p = str;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (p && *p) {
|
|
Packit |
8480eb |
char *next = NULL;
|
|
Packit |
8480eb |
int weight = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p += strspn(p, " \t,");
|
|
Packit |
8480eb |
delim = seek_delim(p);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (delim) {
|
|
Packit |
8480eb |
if (*delim == '(') {
|
|
Packit |
8480eb |
char *w = delim + 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*delim = '\0';
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
delim = strchr(w, ')');
|
|
Packit |
8480eb |
if (delim) {
|
|
Packit |
8480eb |
*delim = '\0';
|
|
Packit |
8480eb |
weight = atoi(w);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
/* syntax error - Mismatched brackets */
|
|
Packit |
8480eb |
free_host_list(hosts);
|
|
Packit |
8480eb |
free(str);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
delim++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (*delim == ':') {
|
|
Packit |
8480eb |
char *path;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
*delim = '\0';
|
|
Packit |
8480eb |
path = delim + 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Oh boy - might have spaces in the path */
|
|
Packit |
8480eb |
next = path;
|
|
Packit |
8480eb |
while (*next && strncmp(next, ":/", 2))
|
|
Packit |
8480eb |
next++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* No spaces in host names at least */
|
|
Packit |
8480eb |
if (*next == ':') {
|
|
Packit |
8480eb |
while (*next &&
|
|
Packit |
8480eb |
(*next != ' ' && *next != '\t'))
|
|
Packit |
8480eb |
next--;
|
|
Packit |
8480eb |
*next++ = '\0';
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (p != delim) {
|
|
Packit Service |
145c60 |
if (!add_host_addrs(hosts, p, weight, options)) {
|
|
Packit |
8480eb |
if (empty) {
|
|
Packit |
8480eb |
p = next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!add_path(*hosts, path, strlen(path))) {
|
|
Packit |
8480eb |
free_host_list(hosts);
|
|
Packit |
8480eb |
free(str);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
if (!add_local_path(hosts, path)) {
|
|
Packit |
8480eb |
p = next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else if (*delim != '\0') {
|
|
Packit |
8480eb |
*delim = '\0';
|
|
Packit |
8480eb |
next = delim + 1;
|
|
Packit |
8480eb |
|
|
Packit Service |
145c60 |
if (!add_host_addrs(hosts, p, weight, options)) {
|
|
Packit |
8480eb |
p = next;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
empty = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
/* syntax error - no mount path */
|
|
Packit |
8480eb |
free_host_list(hosts);
|
|
Packit |
8480eb |
free(str);
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p = next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(str);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void dump_host_list(struct host *hosts)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct host *this;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!hosts)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
this = hosts;
|
|
Packit |
8480eb |
while (this) {
|
|
Packit |
8480eb |
logmsg("name %s path %s version %x proximity %u weight %u cost %u",
|
|
Packit |
8480eb |
this->name, this->path, this->version,
|
|
Packit |
8480eb |
this->proximity, this->weight, this->cost);
|
|
Packit |
8480eb |
this = this->next;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|