summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/mount/network.c34
-rw-r--r--utils/mount/network.h2
-rw-r--r--utils/mount/stropts.c32
3 files changed, 50 insertions, 18 deletions
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 2fdd2c0..4f8c15c 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -611,18 +611,33 @@ out_ok:
* returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
*/
static int nfs_probe_nfsport(const struct sockaddr *sap, const socklen_t salen,
- struct pmap *pmap)
+ struct pmap *pmap, int checkv4)
{
if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
return 1;
if (nfs_mount_data_version >= 4) {
const unsigned int *probe_proto;
+ int ret;
+ struct sockaddr_storage save_sa;
probe_proto = nfs_default_proto();
-
- return nfs_probe_port(sap, salen, pmap,
- probe_nfs3_only, probe_proto);
+ memcpy(&save_sa, sap, salen);
+
+ ret = nfs_probe_port(sap, salen, pmap,
+ probe_nfs3_only, probe_proto);
+ if (!ret || !checkv4 || probe_proto != probe_tcp_first)
+ return ret;
+
+ nfs_set_port((struct sockaddr *)&save_sa, NFS_PORT);
+ ret = nfs_rpc_ping((struct sockaddr *)&save_sa, salen,
+ NFS_PROGRAM, 4, IPPROTO_TCP, NULL);
+ if (ret) {
+ rpc_createerr.cf_stat = RPC_FAILED;
+ rpc_createerr.cf_error.re_errno = EAGAIN;
+ return 0;
+ }
+ return 1;
} else
return nfs_probe_port(sap, salen, pmap,
probe_nfs2_only, probe_udp_only);
@@ -671,7 +686,7 @@ static int nfs_probe_version_fixed(const struct sockaddr *mnt_saddr,
const socklen_t nfs_salen,
struct pmap *nfs_pmap)
{
- if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap))
+ if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap, 0))
return 0;
return nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap);
}
@@ -686,6 +701,8 @@ static int nfs_probe_version_fixed(const struct sockaddr *mnt_saddr,
* @nfs_salen: length of NFS server's address
* @nfs_pmap: IN: partially filled-in NFS RPC service tuple;
* OUT: fully filled-in NFS RPC service tuple
+ * @checkv4: Flag indicating that if v3 is available we must also
+ * check v4, and if that is available, set re_errno to EAGAIN.
*
* Returns 1 and fills in both @pmap structs if the requested service
* ports are unambiguous and pingable. Otherwise zero is returned;
@@ -696,7 +713,8 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr,
struct pmap *mnt_pmap,
const struct sockaddr *nfs_saddr,
const socklen_t nfs_salen,
- struct pmap *nfs_pmap)
+ struct pmap *nfs_pmap,
+ int checkv4)
{
struct pmap save_nfs, save_mnt;
const unsigned long *probe_vers;
@@ -717,7 +735,7 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr,
for (; *probe_vers; probe_vers++) {
nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
- if (nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap) != 0) {
+ if (nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap, checkv4) != 0) {
mnt_pmap->pm_vers = *probe_vers;
if (nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap) != 0)
return 1;
@@ -757,7 +775,7 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
return nfs_probe_bothports(mnt_addr, sizeof(mnt_server->saddr),
&mnt_server->pmap,
nfs_addr, sizeof(nfs_server->saddr),
- &nfs_server->pmap);
+ &nfs_server->pmap, 0);
}
/**
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 9c75856..d7636d7 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -42,7 +42,7 @@ static const struct timeval RETRY_TIMEOUT = { 3, 0 };
int probe_bothports(clnt_addr_t *, clnt_addr_t *);
int nfs_probe_bothports(const struct sockaddr *, const socklen_t,
struct pmap *, const struct sockaddr *,
- const socklen_t, struct pmap *);
+ const socklen_t, struct pmap *, int);
int nfs_gethostbyname(const char *, struct sockaddr_in *);
int nfs_lookup(const char *hostname, const sa_family_t family,
struct sockaddr *sap, socklen_t *salen);
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index a642394..2d72d5b 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -484,7 +484,7 @@ static int nfs_construct_new_options(struct mount_options *options,
* FALSE is returned if some failure occurred.
*/
static int
-nfs_rewrite_pmap_mount_options(struct mount_options *options)
+nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4)
{
union nfs_sockaddr nfs_address;
struct sockaddr *nfs_saddr = &nfs_address.sa;
@@ -534,7 +534,7 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
* negotiate. Bail now if we can't contact it.
*/
if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap,
- nfs_saddr, nfs_salen, &nfs_pmap)) {
+ nfs_saddr, nfs_salen, &nfs_pmap, checkv4)) {
errno = ESPIPE;
if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
errno = EOPNOTSUPP;
@@ -595,7 +595,8 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
}
static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
- struct sockaddr *sap, socklen_t salen)
+ struct sockaddr *sap, socklen_t salen,
+ int checkv4)
{
struct mount_options *options = po_dup(mi->options);
int result = 0;
@@ -637,7 +638,7 @@ static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
printf(_("%s: trying text-based options '%s'\n"),
progname, *mi->extra_opts);
- if (!nfs_rewrite_pmap_mount_options(options))
+ if (!nfs_rewrite_pmap_mount_options(options, checkv4))
goto out_fail;
result = nfs_sys_mount(mi, options);
@@ -653,13 +654,13 @@ out_fail:
* Returns TRUE if successful, otherwise FALSE.
* "errno" is set to reflect the individual error.
*/
-static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
+static int nfs_try_mount_v3v2(struct nfsmount_info *mi, int checkv4)
{
struct addrinfo *ai;
int ret = 0;
for (ai = mi->address; ai != NULL; ai = ai->ai_next) {
- ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen);
+ ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen, checkv4);
if (ret != 0)
return ret;
@@ -793,7 +794,8 @@ static int nfs_autonegotiate(struct nfsmount_info *mi)
result = nfs_try_mount_v4(mi);
if (result)
return result;
-
+
+check_errno:
switch (errno) {
case EPROTONOSUPPORT:
/* A clear indication that the server or our
@@ -807,12 +809,24 @@ static int nfs_autonegotiate(struct nfsmount_info *mi)
/* Linux servers prior to 2.6.25 may return
* EPERM when NFS version 4 is not supported. */
goto fall_back;
+ case ECONNREFUSED:
+ /* UDP-Only servers won't support v4, but maybe it
+ * just isn't ready yet. So try v3, but double-check
+ * with rpcbind for v4. */
+ result = nfs_try_mount_v3v2(mi, TRUE);
+ if (result == 0 && errno == EAGAIN) {
+ /* v4 server seems to be registered now. */
+ result = nfs_try_mount_v4(mi);
+ if (result == 0 && errno != ECONNREFUSED)
+ goto check_errno;
+ }
+ return result;
default:
return result;
}
fall_back:
- return nfs_try_mount_v3v2(mi);
+ return nfs_try_mount_v3v2(mi, FALSE);
}
/*
@@ -831,7 +845,7 @@ static int nfs_try_mount(struct nfsmount_info *mi)
break;
case 2:
case 3:
- result = nfs_try_mount_v3v2(mi);
+ result = nfs_try_mount_v3v2(mi, FALSE);
break;
case 4:
result = nfs_try_mount_v4(mi);