- ignore duplicate exports in auto.net. - add kernel verion check function. - add function to check mount.nfs version. - reinstate singleton mount probe. - rework error return handling in rpc code. - catch EHOSTUNREACH and bail out early. - systemd support fixes. - fix segmentation fault in do_remount_indirect().
619 lines
15 KiB
Diff
619 lines
15 KiB
Diff
autofs-5.0.6 - rework error return handling in rpc code
|
|
|
|
From: Ian Kent <raven@themaw.net>
|
|
|
|
With the changes to the way mount.nfs performs nfs mounts for
|
|
kernels that support passing of text based options mounts to
|
|
hosts that are down or unreachable can take a long time to
|
|
fail due to lengthy timeouts. The kernel rpc code is duty
|
|
bound to honour these timeouts so we need to find a way to
|
|
catch EHOSTUNREACH errors during host probing.
|
|
|
|
The first thing to do is to rework the lower level autofs
|
|
rpc code to propogate error returns up to the higher levels.
|
|
---
|
|
|
|
CHANGELOG | 1
|
|
lib/rpc_subs.c | 178 ++++++++++++++++++++++++++++-----------------------
|
|
modules/replicated.c | 26 +++----
|
|
3 files changed, 114 insertions(+), 91 deletions(-)
|
|
|
|
|
|
--- autofs-5.0.6.orig/CHANGELOG
|
|
+++ autofs-5.0.6/CHANGELOG
|
|
@@ -27,6 +27,7 @@
|
|
- add kernel verion check function.
|
|
- add function to check mount.nfs version.
|
|
- reinstate singleton mount probe.
|
|
+- rework error return handling in rpc code.
|
|
|
|
28/06/2011 autofs-5.0.6
|
|
-----------------------
|
|
--- autofs-5.0.6.orig/lib/rpc_subs.c
|
|
+++ autofs-5.0.6/lib/rpc_subs.c
|
|
@@ -76,11 +76,11 @@ static int connect_nb(int fd, struct soc
|
|
|
|
flags = fcntl(fd, F_GETFL, 0);
|
|
if (flags < 0)
|
|
- return -1;
|
|
+ return -errno;
|
|
|
|
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
if (ret < 0)
|
|
- return -1;
|
|
+ return -errno;
|
|
|
|
/*
|
|
* From here on subsequent sys calls could change errno so
|
|
@@ -150,14 +150,16 @@ done:
|
|
}
|
|
|
|
#ifndef WITH_LIBTIRPC
|
|
-static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd)
|
|
+static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
|
|
{
|
|
- CLIENT *client = NULL;
|
|
+ CLIENT *clnt = NULL;
|
|
struct sockaddr_in in4_laddr;
|
|
struct sockaddr_in *in4_raddr;
|
|
int type, proto;
|
|
socklen_t slen;
|
|
|
|
+ *client = NULL;
|
|
+
|
|
proto = info->proto->p_proto;
|
|
if (proto == IPPROTO_UDP)
|
|
type = SOCK_DGRAM;
|
|
@@ -179,11 +181,11 @@ static CLIENT *rpc_do_create_client(stru
|
|
|
|
*fd = open_sock(addr->sa_family, type, proto);
|
|
if (*fd < 0)
|
|
- return NULL;
|
|
+ return -errno;
|
|
|
|
laddr = (struct sockaddr *) &in4_laddr;
|
|
if (bind(*fd, laddr, slen) < 0)
|
|
- return NULL;
|
|
+ return -errno;
|
|
}
|
|
|
|
in4_raddr = (struct sockaddr_in *) addr;
|
|
@@ -191,26 +193,29 @@ static CLIENT *rpc_do_create_client(stru
|
|
|
|
switch (info->proto->p_proto) {
|
|
case IPPROTO_UDP:
|
|
- client = clntudp_bufcreate(in4_raddr,
|
|
- info->program, info->version,
|
|
- info->timeout, fd,
|
|
- info->send_sz, info->recv_sz);
|
|
+ clnt = clntudp_bufcreate(in4_raddr,
|
|
+ info->program, info->version,
|
|
+ info->timeout, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
break;
|
|
|
|
case IPPROTO_TCP:
|
|
- if (connect_nb(*fd, addr, slen, &info->timeout) < 0)
|
|
- break;
|
|
-
|
|
- client = clnttcp_create(in4_raddr,
|
|
- info->program, info->version, fd,
|
|
- info->send_sz, info->recv_sz);
|
|
+ int ret = connect_nb(*fd, addr, slen, &info->timeout);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ clnt = clnttcp_create(in4_raddr,
|
|
+ info->program, info->version, fd,
|
|
+ info->send_sz, info->recv_sz);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
- return client;
|
|
+ *client = clnt;
|
|
+
|
|
+ return 0;
|
|
}
|
|
#else
|
|
struct netconfig *find_netconf(void *handle, char *family, char *proto)
|
|
@@ -226,9 +231,9 @@ struct netconfig *find_netconf(void *han
|
|
return nconf;
|
|
}
|
|
|
|
-static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd)
|
|
+static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
|
|
{
|
|
- CLIENT *client = NULL;
|
|
+ CLIENT *clnt = NULL;
|
|
struct sockaddr_in in4_laddr;
|
|
struct sockaddr_in6 in6_laddr;
|
|
struct sockaddr *laddr = NULL;
|
|
@@ -238,6 +243,9 @@ static CLIENT *rpc_do_create_client(stru
|
|
char *nc_family, *nc_proto;
|
|
void *handle;
|
|
size_t slen;
|
|
+ int ret;
|
|
+
|
|
+ *client = NULL;
|
|
|
|
proto = info->proto->p_proto;
|
|
if (proto == IPPROTO_UDP) {
|
|
@@ -272,16 +280,16 @@ static CLIENT *rpc_do_create_client(stru
|
|
slen = sizeof(struct sockaddr_in6);
|
|
nc_family = NC_INET6;
|
|
} else
|
|
- return NULL;
|
|
+ return -EINVAL;
|
|
|
|
handle = setnetconfig();
|
|
if (!handle)
|
|
- return NULL;
|
|
+ return -EINVAL;
|
|
|
|
nconf = find_netconf(handle, nc_family, nc_proto);
|
|
if (!nconf) {
|
|
endnetconfig(handle);
|
|
- return NULL;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
@@ -292,13 +300,15 @@ static CLIENT *rpc_do_create_client(stru
|
|
if (!info->client) {
|
|
*fd = open_sock(addr->sa_family, type, proto);
|
|
if (*fd < 0) {
|
|
+ ret = -errno;
|
|
endnetconfig(handle);
|
|
- return NULL;
|
|
+ return ret;
|
|
}
|
|
|
|
if (bind(*fd, laddr, slen) < 0) {
|
|
+ ret = -errno;
|
|
endnetconfig(handle);
|
|
- return NULL;
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
@@ -306,28 +316,30 @@ static CLIENT *rpc_do_create_client(stru
|
|
nb_addr.buf = addr;
|
|
|
|
if (info->proto->p_proto == IPPROTO_TCP) {
|
|
- if (connect_nb(*fd, addr, slen, &info->timeout) < 0) {
|
|
+ ret = connect_nb(*fd, addr, slen, &info->timeout);
|
|
+ if (ret < 0) {
|
|
endnetconfig(handle);
|
|
- return NULL;
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
- client = clnt_tli_create(*fd, nconf, &nb_addr,
|
|
- info->program, info->version,
|
|
- info->send_sz, info->recv_sz);
|
|
+ clnt = clnt_tli_create(*fd, nconf, &nb_addr,
|
|
+ info->program, info->version,
|
|
+ info->send_sz, info->recv_sz);
|
|
|
|
endnetconfig(handle);
|
|
|
|
- return client;
|
|
+ *client = clnt;
|
|
+
|
|
+ return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Create an RPC client
|
|
*/
|
|
-static CLIENT *create_client(struct conn_info *info)
|
|
+static int create_client(struct conn_info *info, CLIENT **client)
|
|
{
|
|
- CLIENT *client = NULL;
|
|
struct addrinfo *ai, *haddr;
|
|
struct addrinfo hints;
|
|
int fd, ret;
|
|
@@ -346,9 +358,11 @@ static CLIENT *create_client(struct conn
|
|
}
|
|
|
|
if (info->addr) {
|
|
- client = rpc_do_create_client(info->addr, info, &fd);
|
|
- if (client)
|
|
+ ret = rpc_do_create_client(info->addr, info, &fd, client);
|
|
+ if (ret == 0)
|
|
goto done;
|
|
+ if (ret == -EHOSTUNREACH)
|
|
+ goto out_close;
|
|
|
|
if (!info->client && fd != RPC_ANYSOCK) {
|
|
close(fd);
|
|
@@ -376,9 +390,11 @@ static CLIENT *create_client(struct conn
|
|
continue;
|
|
}
|
|
|
|
- client = rpc_do_create_client(haddr->ai_addr, info, &fd);
|
|
- if (client)
|
|
+ ret = rpc_do_create_client(haddr->ai_addr, info, &fd, client);
|
|
+ if (ret == 0)
|
|
break;
|
|
+ if (ret == -EHOSTUNREACH)
|
|
+ goto out_close;
|
|
|
|
if (!info->client && fd != RPC_ANYSOCK) {
|
|
close(fd);
|
|
@@ -390,24 +406,26 @@ static CLIENT *create_client(struct conn
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
- if (!client) {
|
|
+ if (!*client) {
|
|
info->client = NULL;
|
|
+ ret = -ENOTCONN;
|
|
goto out_close;
|
|
}
|
|
done:
|
|
/* Close socket fd on destroy, as is default for rpcowned fds */
|
|
- if (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
|
|
- clnt_destroy(client);
|
|
+ if (!clnt_control(*client, CLSET_FD_CLOSE, NULL)) {
|
|
+ clnt_destroy(*client);
|
|
info->client = NULL;
|
|
+ ret = -ENOTCONN;
|
|
goto out_close;
|
|
}
|
|
|
|
- return client;
|
|
+ return 0;
|
|
|
|
out_close:
|
|
if (fd != -1)
|
|
close(fd);
|
|
- return NULL;
|
|
+ return ret;
|
|
}
|
|
|
|
int rpc_udp_getclient(struct conn_info *info,
|
|
@@ -415,11 +433,12 @@ int rpc_udp_getclient(struct conn_info *
|
|
{
|
|
struct protoent *pe_proto;
|
|
CLIENT *client;
|
|
+ int ret;
|
|
|
|
if (!info->client) {
|
|
pe_proto = getprotobyname("udp");
|
|
if (!pe_proto)
|
|
- return 0;
|
|
+ return -ENOENT;
|
|
|
|
info->proto = pe_proto;
|
|
info->send_sz = UDPMSGSIZE;
|
|
@@ -429,14 +448,13 @@ int rpc_udp_getclient(struct conn_info *
|
|
info->program = program;
|
|
info->version = version;
|
|
|
|
- client = create_client(info);
|
|
-
|
|
- if (!client)
|
|
- return 0;
|
|
+ ret = create_client(info, &client);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
|
|
info->client = client;
|
|
|
|
- return 1;
|
|
+ return 0;
|
|
}
|
|
|
|
void rpc_destroy_udp_client(struct conn_info *info)
|
|
@@ -454,11 +472,12 @@ int rpc_tcp_getclient(struct conn_info *
|
|
{
|
|
struct protoent *pe_proto;
|
|
CLIENT *client;
|
|
+ int ret;
|
|
|
|
if (!info->client) {
|
|
pe_proto = getprotobyname("tcp");
|
|
if (!pe_proto)
|
|
- return 0;
|
|
+ return -ENOENT;
|
|
|
|
info->proto = pe_proto;
|
|
info->send_sz = 0;
|
|
@@ -468,14 +487,13 @@ int rpc_tcp_getclient(struct conn_info *
|
|
info->program = program;
|
|
info->version = version;
|
|
|
|
- client = create_client(info);
|
|
-
|
|
- if (!client)
|
|
- return 0;
|
|
+ ret = create_client(info, &client);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
|
|
info->client = client;
|
|
|
|
- return 1;
|
|
+ return 0;
|
|
}
|
|
|
|
void rpc_destroy_tcp_client(struct conn_info *info)
|
|
@@ -509,10 +527,11 @@ int rpc_portmap_getclient(struct conn_in
|
|
{
|
|
struct protoent *pe_proto;
|
|
CLIENT *client;
|
|
+ int ret;
|
|
|
|
pe_proto = getprotobyname(proto);
|
|
if (!pe_proto)
|
|
- return 0;
|
|
+ return -ENOENT;
|
|
|
|
info->host = host;
|
|
info->addr = addr;
|
|
@@ -530,13 +549,14 @@ int rpc_portmap_getclient(struct conn_in
|
|
|
|
if (pe_proto->p_proto == IPPROTO_TCP)
|
|
info->timeout.tv_sec = PMAP_TOUT_TCP;
|
|
- client = create_client(info);
|
|
- if (!client)
|
|
- return 0;
|
|
+
|
|
+ ret = create_client(info, &client);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
|
|
info->client = client;
|
|
|
|
- return 1;
|
|
+ return 0;
|
|
}
|
|
|
|
unsigned short rpc_portmap_getport(struct conn_info *info, struct pmap *parms)
|
|
@@ -546,6 +566,7 @@ unsigned short rpc_portmap_getport(struc
|
|
CLIENT *client;
|
|
enum clnt_stat status;
|
|
int proto = info->proto->p_proto;
|
|
+ int ret;
|
|
|
|
memset(&pmap_info, 0, sizeof(struct conn_info));
|
|
|
|
@@ -567,9 +588,9 @@ unsigned short rpc_portmap_getport(struc
|
|
pmap_info.send_sz = RPCSMALLMSGSIZE;
|
|
pmap_info.recv_sz = RPCSMALLMSGSIZE;
|
|
|
|
- client = create_client(&pmap_info);
|
|
- if (!client)
|
|
- return 0;
|
|
+ ret = create_client(&pmap_info, &client);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
}
|
|
|
|
/*
|
|
@@ -611,7 +632,7 @@ unsigned short rpc_portmap_getport(struc
|
|
}
|
|
|
|
if (status != RPC_SUCCESS)
|
|
- return 0;
|
|
+ return -EIO;
|
|
|
|
return port;
|
|
}
|
|
@@ -621,6 +642,7 @@ int rpc_ping_proto(struct conn_info *inf
|
|
CLIENT *client;
|
|
enum clnt_stat status;
|
|
int proto = info->proto->p_proto;
|
|
+ int ret;
|
|
|
|
if (info->client)
|
|
client = info->client;
|
|
@@ -629,9 +651,9 @@ int rpc_ping_proto(struct conn_info *inf
|
|
info->send_sz = UDPMSGSIZE;
|
|
info->recv_sz = UDPMSGSIZE;
|
|
}
|
|
- client = create_client(info);
|
|
- if (!client)
|
|
- return 0;
|
|
+ ret = create_client(info, &client);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
}
|
|
|
|
clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
|
|
@@ -665,7 +687,7 @@ int rpc_ping_proto(struct conn_info *inf
|
|
}
|
|
|
|
if (status != RPC_SUCCESS)
|
|
- return 0;
|
|
+ return -EIO;
|
|
|
|
return 1;
|
|
}
|
|
@@ -704,7 +726,7 @@ static unsigned int __rpc_ping(const cha
|
|
parms.pm_port = 0;
|
|
|
|
info.port = rpc_portmap_getport(&info, &parms);
|
|
- if (!info.port)
|
|
+ if (info.port < 0)
|
|
return status;
|
|
|
|
status = rpc_ping_proto(&info);
|
|
@@ -719,19 +741,19 @@ int rpc_ping(const char *host, long seco
|
|
unsigned int status;
|
|
|
|
status = __rpc_ping(host, vers2, "udp", seconds, micros, option);
|
|
- if (status)
|
|
+ if (status > 0)
|
|
return RPC_PING_V2 | RPC_PING_UDP;
|
|
|
|
status = __rpc_ping(host, vers3, "udp", seconds, micros, option);
|
|
- if (status)
|
|
+ if (status > 0)
|
|
return RPC_PING_V3 | RPC_PING_UDP;
|
|
|
|
status = __rpc_ping(host, vers2, "tcp", seconds, micros, option);
|
|
- if (status)
|
|
+ if (status > 0)
|
|
return RPC_PING_V2 | RPC_PING_TCP;
|
|
|
|
status = __rpc_ping(host, vers3, "tcp", seconds, micros, option);
|
|
- if (status)
|
|
+ if (status > 0)
|
|
return RPC_PING_V3 | RPC_PING_TCP;
|
|
|
|
return status;
|
|
@@ -760,9 +782,8 @@ int rpc_time(const char *host,
|
|
status = __rpc_ping(host, vers, proto, seconds, micros, option);
|
|
gettimeofday(&end, &tz);
|
|
|
|
- if (!status) {
|
|
- return 0;
|
|
- }
|
|
+ if (status == RPC_PING_FAIL || status < 0)
|
|
+ return status;
|
|
|
|
taken = elapsed(start, end);
|
|
|
|
@@ -779,13 +800,14 @@ static int rpc_get_exports_proto(struct
|
|
int proto = info->proto->p_proto;
|
|
unsigned int option = info->close_option;
|
|
int vers_entry;
|
|
+ int ret;
|
|
|
|
if (info->proto->p_proto == IPPROTO_UDP) {
|
|
info->send_sz = UDPMSGSIZE;
|
|
info->recv_sz = UDPMSGSIZE;
|
|
}
|
|
- client = create_client(info);
|
|
- if (!client)
|
|
+ ret = create_client(info, &client);
|
|
+ if (ret < 0)
|
|
return 0;
|
|
|
|
clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
|
|
@@ -894,7 +916,7 @@ exports rpc_get_exports(const char *host
|
|
parms.pm_prot = info.proto->p_proto;
|
|
|
|
info.port = rpc_portmap_getport(&info, &parms);
|
|
- if (!info.port)
|
|
+ if (info.port < 0)
|
|
goto try_tcp;
|
|
|
|
memset(&exportlist, '\0', sizeof(exportlist));
|
|
@@ -911,7 +933,7 @@ try_tcp:
|
|
parms.pm_prot = info.proto->p_proto;
|
|
|
|
info.port = rpc_portmap_getport(&info, &parms);
|
|
- if (!info.port)
|
|
+ if (info.port < 0)
|
|
return NULL;
|
|
|
|
memset(&exportlist, '\0', sizeof(exportlist));
|
|
--- autofs-5.0.6.orig/modules/replicated.c
|
|
+++ autofs-5.0.6/modules/replicated.c
|
|
@@ -563,11 +563,11 @@ static unsigned int get_nfs_info(unsigne
|
|
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
|
|
else
|
|
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
|
|
- if (status) {
|
|
+ if (!status) {
|
|
gettimeofday(&start, &tz);
|
|
status = rpc_ping_proto(rpc_info);
|
|
gettimeofday(&end, &tz);
|
|
- if (status) {
|
|
+ if (status > 0) {
|
|
double reply;
|
|
if (random_selection) {
|
|
/* Random value between 0 and 1 */
|
|
@@ -589,7 +589,7 @@ v3_ver:
|
|
status = rpc_portmap_getclient(pm_info,
|
|
host->name, host->addr, host->addr_len,
|
|
proto, RPC_CLOSE_DEFAULT);
|
|
- if (!status)
|
|
+ if (status)
|
|
goto done_ver;
|
|
}
|
|
|
|
@@ -603,7 +603,7 @@ v3_ver:
|
|
parms.pm_prot = rpc_info->proto->p_proto;
|
|
parms.pm_vers = NFS3_VERSION;
|
|
rpc_info->port = rpc_portmap_getport(pm_info, &parms);
|
|
- if (!rpc_info->port)
|
|
+ if (rpc_info->port < 0)
|
|
goto v2_ver;
|
|
}
|
|
|
|
@@ -611,11 +611,11 @@ v3_ver:
|
|
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
|
|
else
|
|
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
|
|
- if (status) {
|
|
+ if (!status) {
|
|
gettimeofday(&start, &tz);
|
|
status = rpc_ping_proto(rpc_info);
|
|
gettimeofday(&end, &tz);
|
|
- if (status) {
|
|
+ if (status > 0) {
|
|
double reply;
|
|
if (random_selection) {
|
|
/* Random value between 0 and 1 */
|
|
@@ -643,7 +643,7 @@ v2_ver:
|
|
parms.pm_prot = rpc_info->proto->p_proto;
|
|
parms.pm_vers = NFS2_VERSION;
|
|
rpc_info->port = rpc_portmap_getport(pm_info, &parms);
|
|
- if (!rpc_info->port)
|
|
+ if (rpc_info->port < 0)
|
|
goto done_ver;
|
|
}
|
|
|
|
@@ -651,11 +651,11 @@ v2_ver:
|
|
status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
|
|
else
|
|
status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
|
|
- if (status) {
|
|
+ if (!status) {
|
|
gettimeofday(&start, &tz);
|
|
status = rpc_ping_proto(rpc_info);
|
|
gettimeofday(&end, &tz);
|
|
- if (status) {
|
|
+ if (status > 0) {
|
|
double reply;
|
|
if (random_selection) {
|
|
/* Random value between 0 and 1 */
|
|
@@ -835,12 +835,12 @@ static int get_supported_ver_and_cost(un
|
|
int ret = rpc_portmap_getclient(&pm_info,
|
|
host->name, host->addr, host->addr_len,
|
|
proto, RPC_CLOSE_DEFAULT);
|
|
- if (!ret)
|
|
+ if (ret)
|
|
return 0;
|
|
|
|
parms.pm_prot = rpc_info.proto->p_proto;
|
|
rpc_info.port = rpc_portmap_getport(&pm_info, &parms);
|
|
- if (!rpc_info.port)
|
|
+ if (rpc_info.port < 0)
|
|
goto done;
|
|
}
|
|
|
|
@@ -848,11 +848,11 @@ static int get_supported_ver_and_cost(un
|
|
status = rpc_udp_getclient(&rpc_info, NFS_PROGRAM, parms.pm_vers);
|
|
else
|
|
status = rpc_tcp_getclient(&rpc_info, NFS_PROGRAM, parms.pm_vers);
|
|
- if (status) {
|
|
+ if (!status) {
|
|
gettimeofday(&start, &tz);
|
|
status = rpc_ping_proto(&rpc_info);
|
|
gettimeofday(&end, &tz);
|
|
- if (status) {
|
|
+ if (status > 0) {
|
|
if (random_selection) {
|
|
/* Random value between 0 and 1 */
|
|
taken = ((float) random())/((float) RAND_MAX+1);
|