From 852424a9a02dbe1a7c3b75a014bc71cad2ab6d5e Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 21 Jul 2008 12:45:50 +1000 References: bnc#404170 Subject: [PATCH] Check nfs options (vers/protocol) before trying mount. As the kernels nfs-mount client does not have heuristics to pick the best protocol/version, also check with portmap to find what is available before requesting a mount. However don't try to 'ping' the services. For NFS, this ping would need to come from a reserved port, and these are a scarce resource. If the mount found, retry the probe doing any ping that might be needed in the hope of finding the problem. Note: this patch also removes the (recently added) setting of mountport= in the mount arguments. This is because: 1/ the kernel can find it easily itself 2/ it could confuse unmount which may be run much later when mountd is running on a different port. Signed-off-by: Neil Brown --- utils/mount/network.c | 35 +++++++++++++++++++++-------------- utils/mount/network.h | 2 +- utils/mount/nfsmount.c | 2 +- utils/mount/stropts.c | 18 +++++++----------- 4 files changed, 30 insertions(+), 27 deletions(-) --- nfs-utils-1.1.3.orig/utils/mount/network.c +++ nfs-utils-1.1.3/utils/mount/network.c @@ -500,9 +500,11 @@ static unsigned short getport(struct soc * Use the portmapper to discover whether or not the service we want is * available. The lists 'versions' and 'protos' define ordered sequences * of service versions and udp/tcp protocols to probe for. + * If 'ping' is set, set an RPC NULL request to make sure the service + * is there. Else just assume that it is. */ static int probe_port(clnt_addr_t *server, const unsigned long *versions, - const unsigned int *protos) + const unsigned int *protos, int ping) { struct sockaddr_in *saddr = &server->saddr; struct pmap *pmap = &server->pmap; @@ -530,7 +532,8 @@ static int probe_port(clnt_addr_t *serve _("UDP") : _("TCP"), p_port); } - if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL)) + if (!ping || + clnt_ping(saddr, prog, *p_vers, *p_prot, NULL)) goto out_ok; } } @@ -565,7 +568,7 @@ out_ok: return 1; } -static int probe_nfsport(clnt_addr_t *nfs_server) +static int probe_nfsport(clnt_addr_t *nfs_server, int ping) { struct pmap *pmap = &nfs_server->pmap; @@ -573,12 +576,14 @@ static int probe_nfsport(clnt_addr_t *nf return 1; if (nfs_mount_data_version >= 4) - return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first); + return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first, + ping); else - return probe_port(nfs_server, probe_nfs2_only, probe_udp_only); + return probe_port(nfs_server, probe_nfs2_only, probe_udp_only, + ping); } -static int probe_mntport(clnt_addr_t *mnt_server) +static int probe_mntport(clnt_addr_t *mnt_server, int ping) { struct pmap *pmap = &mnt_server->pmap; @@ -586,9 +591,11 @@ static int probe_mntport(clnt_addr_t *mn return 1; if (nfs_mount_data_version >= 4) - return probe_port(mnt_server, probe_mnt3_first, probe_udp_first); + return probe_port(mnt_server, probe_mnt3_first, probe_udp_first, + ping); else - return probe_port(mnt_server, probe_mnt1_first, probe_udp_only); + return probe_port(mnt_server, probe_mnt1_first, probe_udp_only, + ping); } /** @@ -601,7 +608,7 @@ static int probe_mntport(clnt_addr_t *mn * * A side effect of calling this function is that rpccreateerr is set. */ -int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) +int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server, int ping) { struct pmap *nfs_pmap = &nfs_server->pmap; struct pmap *mnt_pmap = &mnt_server->pmap; @@ -623,9 +630,9 @@ int probe_bothports(clnt_addr_t *mnt_ser for (; *probe_vers; probe_vers++) { nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers); - if ((res = probe_nfsport(nfs_server) != 0)) { + if ((res = probe_nfsport(nfs_server, ping) != 0)) { mnt_pmap->pm_vers = *probe_vers; - if ((res = probe_mntport(mnt_server)) != 0) + if ((res = probe_mntport(mnt_server, ping)) != 0) return 1; memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap)); } @@ -643,9 +650,9 @@ out_bad: return 0; version_fixed: - if (!probe_nfsport(nfs_server)) + if (!probe_nfsport(nfs_server, ping)) goto out_bad; - return probe_mntport(mnt_server); + return probe_mntport(mnt_server, ping); } static int probe_statd(void) @@ -712,7 +719,7 @@ int nfs_call_umount(clnt_addr_t *mnt_ser enum clnt_stat res = 0; int msock; - if (!probe_mntport(mnt_server)) + if (!probe_mntport(mnt_server, 0)) return 0; clnt = mnt_openclnt(mnt_server, &msock); if (!clnt) --- nfs-utils-1.1.3.orig/utils/mount/network.h +++ nfs-utils-1.1.3/utils/mount/network.h @@ -39,7 +39,7 @@ typedef struct { static const struct timeval TIMEOUT = { 20, 0 }; static const struct timeval RETRY_TIMEOUT = { 3, 0 }; -int probe_bothports(clnt_addr_t *, clnt_addr_t *); +int probe_bothports(clnt_addr_t *, clnt_addr_t *, int); int nfs_gethostbyname(const char *, struct sockaddr_in *); int nfs_name_to_address(const char *, const sa_family_t, struct sockaddr *, socklen_t *); --- nfs-utils-1.1.3.orig/utils/mount/nfsmount.c +++ nfs-utils-1.1.3/utils/mount/nfsmount.c @@ -129,7 +129,7 @@ nfs_call_mount(clnt_addr_t *mnt_server, enum clnt_stat stat; int msock; - if (!probe_bothports(mnt_server, nfs_server)) + if (!probe_bothports(mnt_server, nfs_server, 1)) goto out_bad; clnt = mnt_openclnt(mnt_server, &msock); --- nfs-utils-1.1.3.orig/utils/mount/stropts.c +++ nfs-utils-1.1.3/utils/mount/stropts.c @@ -314,7 +314,7 @@ static int nfs_is_permanent_error(int er * Returns a new group of mount options if successful; otherwise * NULL is returned if some failure occurred. */ -static struct mount_options *nfs_rewrite_mount_options(char *str) +static struct mount_options *nfs_rewrite_mount_options(char *str, int ping) { struct mount_options *options; char *option, new_option[64]; @@ -405,7 +405,7 @@ static struct mount_options *nfs_rewrite po_remove_all(options, "tcp"); po_remove_all(options, "udp"); - if (!probe_bothports(&mnt_server, &nfs_server)) { + if (!probe_bothports(&mnt_server, &nfs_server, ping)) { errno = ESPIPE; goto err; } @@ -441,11 +441,6 @@ static struct mount_options *nfs_rewrite if (po_append(options, new_option) == PO_FAILED) goto err; - snprintf(new_option, sizeof(new_option) - 1, - "mountport=%lu", mnt_server.pmap.pm_port); - if (po_append(options, new_option) == PO_FAILED) - goto err; - errno = 0; return options; @@ -486,13 +481,13 @@ static int nfs_sys_mount(const struct nf * 'extra_opts' are updated to reflect the mount options that worked. * If the retry fails, 'options' and 'extra_opts' are left unchanged. */ -static int nfs_retry_nfs23mount(struct nfsmount_info *mi) +static int nfs_try_nfs23mount_probe(struct nfsmount_info *mi, int ping) { struct mount_options *retry_options; char *retry_str = NULL; char **extra_opts = mi->extra_opts; - retry_options = nfs_rewrite_mount_options(*extra_opts); + retry_options = nfs_rewrite_mount_options(*extra_opts, ping); if (!retry_options) return 0; @@ -547,7 +542,7 @@ static int nfs_try_nfs23mount(struct nfs if (mi->fake) return 1; - if (nfs_sys_mount(mi, "nfs", *extra_opts)) + if (nfs_try_nfs23mount_probe(mi, 0)) return 1; /* @@ -557,7 +552,8 @@ static int nfs_try_nfs23mount(struct nfs if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT) return 0; - return nfs_retry_nfs23mount(mi); + /* Probe harder */ + return nfs_try_nfs23mount_probe(mi, 1); } /*