summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient/nfs_socket.c
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1999-12-13 04:24:55 +0000
committerdillon <dillon@FreeBSD.org>1999-12-13 04:24:55 +0000
commit275dfe67561c202ecdd08ae38f054802f440989a (patch)
tree1db83b6396203cfa886bdb1d4703da2a8bae2594 /sys/nfsclient/nfs_socket.c
parent65600d1d6d0331ad1e8f91f29c2118eb0a90e7d5 (diff)
downloadFreeBSD-src-275dfe67561c202ecdd08ae38f054802f440989a.zip
FreeBSD-src-275dfe67561c202ecdd08ae38f054802f440989a.tar.gz
Fix a timeout deadlock that can occur when the process holding the
receive lock hasn't yet managed to send its own request. PR: kern/15055 Submitted by: Ian Dowse iedowse@maths.tcd.ie
Diffstat (limited to 'sys/nfsclient/nfs_socket.c')
-rw-r--r--sys/nfsclient/nfs_socket.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c
index 0b314b1..0bf85c0 100644
--- a/sys/nfsclient/nfs_socket.c
+++ b/sys/nfsclient/nfs_socket.c
@@ -152,6 +152,7 @@ static void nfs_rcvunlock __P((struct nfsreq *));
static void nfs_realign __P((struct mbuf **pm, int hsiz));
static int nfs_receive __P((struct nfsreq *rep, struct sockaddr **aname,
struct mbuf **mp));
+static void nfs_softterm __P((struct nfsreq *rep));
static int nfs_reconnect __P((struct nfsreq *rep));
#ifndef NFS_NOSERVER
static int nfsrv_getstream __P((struct nfssvc_sock *,int));
@@ -864,8 +865,10 @@ nfsmout:
if (nmp->nm_cwnd > NFS_MAXCWND)
nmp->nm_cwnd = NFS_MAXCWND;
}
- rep->r_flags &= ~R_SENT;
- nmp->nm_sent -= NFS_CWNDSCALE;
+ if (rep->r_flags & R_SENT) {
+ rep->r_flags &= ~R_SENT;
+ nmp->nm_sent -= NFS_CWNDSCALE;
+ }
/*
* Update rtt using a gain of 0.125 on the mean
* and a gain of 0.25 on the deviation.
@@ -1384,7 +1387,7 @@ nfs_timer(arg)
if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
continue;
if (nfs_sigintr(nmp, rep, rep->r_procp)) {
- rep->r_flags |= R_SOFTTERM;
+ nfs_softterm(rep);
continue;
}
if (rep->r_rtt >= 0) {
@@ -1412,7 +1415,7 @@ nfs_timer(arg)
}
if (rep->r_rexmit >= rep->r_retry) { /* too many */
nfsstats.rpctimeouts++;
- rep->r_flags |= R_SOFTTERM;
+ nfs_softterm(rep);
continue;
}
if (nmp->nm_sotype != SOCK_DGRAM) {
@@ -1491,6 +1494,23 @@ nfs_timer(arg)
nfs_timer_handle = timeout(nfs_timer, (void *)0, nfs_ticks);
}
+/*
+ * Flag a request as being about to terminate (due to NFSMNT_INT/NFSMNT_SOFT).
+ * The nm_send count is decremented now to avoid deadlocks when the process in
+ * soreceive() hasn't yet managed to send its own request.
+ */
+
+static void
+nfs_softterm(rep)
+ struct nfsreq *rep;
+{
+ rep->r_flags |= R_SOFTTERM;
+
+ if (rep->r_flags & R_SENT) {
+ rep->r_nmp->nm_sent -= NFS_CWNDSCALE;
+ rep->r_flags &= ~R_SENT;
+ }
+}
/*
* Test for a termination condition pending on the process.
OpenPOWER on IntegriCloud