summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs_krpc.c62
1 files changed, 56 insertions, 6 deletions
diff --git a/sys/nfsclient/nfs_krpc.c b/sys/nfsclient/nfs_krpc.c
index c2406d9..0389d29 100644
--- a/sys/nfsclient/nfs_krpc.c
+++ b/sys/nfsclient/nfs_krpc.c
@@ -191,6 +191,7 @@ nfs_connect(struct nfsmount *nmp)
struct netconfig *nconf;
rpcvers_t vers;
int one = 1, retries;
+ struct timeval timo;
/*
* We need to establish the socket using the credentials of
@@ -258,12 +259,37 @@ nfs_connect(struct nfsmount *nmp)
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
if (nmp->nm_flag & NFSMNT_RESVPORT)
CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
- if (nmp->nm_flag & NFSMNT_SOFT)
- retries = nmp->nm_retry;
- else
+ if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
+ if (nmp->nm_sotype == SOCK_DGRAM)
+ /*
+ * For UDP, the large timeout for a reconnect will
+ * be set to "nm_retry * nm_timeo / 2", so we only
+ * want to do 2 reconnect timeout retries.
+ */
+ retries = 2;
+ else
+ retries = nmp->nm_retry;
+ } else
retries = INT_MAX;
CLNT_CONTROL(client, CLSET_RETRIES, &retries);
+ /*
+ * For UDP, there are 2 timeouts:
+ * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
+ * that does a retransmit of an RPC request using the same socket
+ * and xid. This is what you normally want to do, since NFS
+ * servers depend on "same xid" for their Duplicate Request Cache.
+ * - timeout specified in CLNT_CALL_MBUF(), which specifies when
+ * retransmits on the same socket should fail and a fresh socket
+ * created. Each of these timeouts counts as one CLSET_RETRIES,
+ * as set above.
+ * Set the initial retransmit timeout for UDP. This timeout doesn't
+ * exist for TCP and the following call just fails, which is ok.
+ */
+ timo.tv_sec = nmp->nm_timeo / NFS_HZ;
+ timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);
+
mtx_lock(&nmp->nm_mtx);
if (nmp->nm_client) {
/*
@@ -411,7 +437,7 @@ nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum,
struct mbuf *md;
time_t waituntil;
caddr_t dpos;
- int error = 0;
+ int error = 0, timeo;
struct timeval now;
AUTH *auth = NULL;
enum nfs_rto_timer_t timer;
@@ -486,8 +512,32 @@ nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum,
nfsstats.rpcrequests++;
tryagain:
- timo.tv_sec = nmp->nm_timeo / NFS_HZ;
- timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ;
+ /*
+ * This timeout specifies when a new socket should be created,
+ * along with new xid values. For UDP, this should be done
+ * infrequently, since retransmits of RPC requests should normally
+ * use the same xid.
+ */
+ if (nmp->nm_sotype == SOCK_DGRAM) {
+ if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
+ /*
+ * CLSET_RETRIES is set to 2, so this should be half
+ * of the total timeout required.
+ */
+ timeo = nmp->nm_retry * nmp->nm_timeo / 2;
+ if (timeo < 1)
+ timeo = 1;
+ timo.tv_sec = timeo / NFS_HZ;
+ timo.tv_usec = (timeo % NFS_HZ) * 1000000 / NFS_HZ;
+ } else {
+ /* For UDP hard mounts, use a large value. */
+ timo.tv_sec = NFS_MAXTIMEO / NFS_HZ;
+ timo.tv_usec = 0;
+ }
+ } else {
+ timo.tv_sec = nmp->nm_timeo / NFS_HZ;
+ timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
+ }
mrep = NULL;
stat = CLNT_CALL_MBUF(nmp->nm_client, &ext,
(nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum],
OpenPOWER on IntegriCloud