From: Neil Brown Subject: [PATCH] mount: enable retry for nfs23 to set the correct protocol for mount. Date: Tue, 15 Jul 2008 22:56:50 +1000 Message-ID: <18556.40594.897682.204554@notabene.brown> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: linux-nfs@vger.kernel.org To: Steve Dickson , "Chuck Lever" Return-path: Received: from mx2.suse.de ([195.135.220.15]:55053 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753743AbYGOM4x (ORCPT ); Tue, 15 Jul 2008 08:56:53 -0400 Sender: linux-nfs-owner@vger.kernel.org List-ID: This is the promised patch that adds mountproto=tcp to the string mount options if needed. We still get a 90second timeout, but at least it works rather than saying "mount.nfs: internal error". It seems to me that it would be best to avoid the first call to mount altogether. Simply always do a probe_both and then do a mount based on the results of that. Is there a good reason not to? BTW, I tested this by running iptables -A INPUT -p udp --dport 111 -j REJECT on the NFS server. Accessing an NFS server over an SSH tunnel would also be a good test that people are using in real life (IRL as my son says...). NeilBrown >From cec4bf512cce4686ed5dd25a9bb489f9e521721d Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 15 Jul 2008 22:38:17 +1000 If an NFS server is only listening on TCP for portmap (as apparently MS-Windows-Server2003R2SP2 does), mount doesn't cope. There is retry logic in case the initial choice of version/etc doesn't work, but it doesn't cope with mountd needing tcp. So: Fix probe_port so that a TIMEDOUT error doesn't simply abort but probes with other protocols (e.g. tcp). Fix rewrite_mount_options to extract the mountproto option before doing a probe, then set mountproto (and mount prot) based on the result. Enable retry if the mount call returns EIO, as that is what happens if the UDP requests to portmap get no response. Signed-off-by: Neil Brown --- utils/mount/network.c | 6 ++++-- utils/mount/stropts.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/utils/mount/network.c b/utils/mount/network.c index ab7f6d0..cde6b2c 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -408,11 +408,10 @@ static int probe_port(clnt_addr_t *server, const unsigned long *versions, } if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL)) goto out_ok; - if (rpc_createerr.cf_stat == RPC_TIMEDOUT) - goto out_bad; } } if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED && + rpc_createerr.cf_stat != RPC_TIMEDOUT && rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH) goto out_bad; @@ -421,6 +420,9 @@ static int probe_port(clnt_addr_t *server, const unsigned long *versions, continue; p_prot = protos; } + if (rpc_createerr.cf_stat == RPC_TIMEDOUT) + goto out_bad; + if (vers || !*++p_vers) break; } diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 967fd69..f06e313 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -386,6 +386,17 @@ static struct mount_options *rewrite_mount_options(char *str) option = po_get(options, "mountvers"); if (option) mnt_server.pmap.pm_vers = atoi(option); + option = po_get(options, "mountproto"); + if (option) { + if (strcmp(option, "tcp") == 0) { + mnt_server.pmap.pm_prot = IPPROTO_TCP; + po_remove_all(options, "mountproto"); + } + if (strcmp(option, "udp") == 0) { + mnt_server.pmap.pm_prot = IPPROTO_UDP; + po_remove_all(options, "mountproto"); + } + } option = po_get(options, "port"); if (option) { @@ -454,6 +465,20 @@ static struct mount_options *rewrite_mount_options(char *str) } + if (mnt_server.pmap.pm_prot == IPPROTO_TCP) + snprintf(new_option, sizeof(new_option) - 1, + "mountproto=tcp"); + else + snprintf(new_option, sizeof(new_option) - 1, + "mountproto=udp"); + 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; @@ -560,9 +585,11 @@ static int nfs_try_nfs23mount(struct nfsmount_info *mi) /* * The kernel returns EOPNOTSUPP if the RPC bind failed, - * and EPROTONOSUPPORT if the version isn't supported. + * and EPROTONOSUPPORT if the version isn't supported, + * and EIO if the protocol doesn't work. */ - if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT) + if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT && + errno != EIO) return 0; return nfs_retry_nfs23mount(mi); -- 1.5.6.2