aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2011-12-05 15:40:30 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-01-05 10:42:39 -0500
commit43717c7daebf10b43f12e68512484b3095bb1ba5 (patch)
tree0c3465ca158dc0d582a8645edfb6d16377afdf5f /init
parent68c97153fb7f2877f98aa6c29546381d9cad2fed (diff)
NFS: Retry mounting NFSROOT
Lukas Razik <linux@razik.name> reports that on his SPARC system, booting with an NFS root file system stopped working after commit 56463e50 "NFS: Use super.c for NFSROOT mount option parsing." We found that the network switch to which Lukas' client was attached was delaying access to the LAN after the client's NIC driver reported that its link was up. The delay was longer than the timeouts used in the NFS client during mounting. NFSROOT worked for Lukas before commit 56463e50 because in those kernels, the client's first operation was an rpcbind request to determine which port the NFS server was listening on. When that request failed after a long timeout, the client simply selected the default NFS port (2049). By that time the switch was allowing access to the LAN, and the mount succeeded. Neither of these client behaviors is desirable, so reverting 56463e50 is really not a choice. Instead, introduce a mechanism that retries the NFSROOT mount request several times. This is the same tactic that normal user space NFS mounts employ to overcome server and network delays. Signed-off-by: Lukas Razik <linux@razik.name> [ cel: match kernel coding style, add proper patch description ] [ cel: add exponential back-off ] Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Tested-by: Lukas Razik <linux@razik.name> Cc: stable@kernel.org # > 2.6.38 Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'init')
-rw-r--r--init/do_mounts.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 0f6e1d985a3b..db6e5ee0e1db 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -398,15 +398,42 @@ out:
398} 398}
399 399
400#ifdef CONFIG_ROOT_NFS 400#ifdef CONFIG_ROOT_NFS
401
402#define NFSROOT_TIMEOUT_MIN 5
403#define NFSROOT_TIMEOUT_MAX 30
404#define NFSROOT_RETRY_MAX 5
405
401static int __init mount_nfs_root(void) 406static int __init mount_nfs_root(void)
402{ 407{
403 char *root_dev, *root_data; 408 char *root_dev, *root_data;
409 unsigned int timeout;
410 int try, err;
404 411
405 if (nfs_root_data(&root_dev, &root_data) != 0) 412 err = nfs_root_data(&root_dev, &root_data);
406 return 0; 413 if (err != 0)
407 if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0)
408 return 0; 414 return 0;
409 return 1; 415
416 /*
417 * The server or network may not be ready, so try several
418 * times. Stop after a few tries in case the client wants
419 * to fall back to other boot methods.
420 */
421 timeout = NFSROOT_TIMEOUT_MIN;
422 for (try = 1; ; try++) {
423 err = do_mount_root(root_dev, "nfs",
424 root_mountflags, root_data);
425 if (err == 0)
426 return 1;
427 if (try > NFSROOT_RETRY_MAX)
428 break;
429
430 /* Wait, in case the server refused us immediately */
431 ssleep(timeout);
432 timeout <<= 1;
433 if (timeout > NFSROOT_TIMEOUT_MAX)
434 timeout = NFSROOT_TIMEOUT_MAX;
435 }
436 return 0;
410} 437}
411#endif 438#endif
412 439