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);