diff options
author | dillon <dillon@FreeBSD.org> | 1999-12-13 04:24:55 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 1999-12-13 04:24:55 +0000 |
commit | 275dfe67561c202ecdd08ae38f054802f440989a (patch) | |
tree | 1db83b6396203cfa886bdb1d4703da2a8bae2594 | |
parent | 65600d1d6d0331ad1e8f91f29c2118eb0a90e7d5 (diff) | |
download | FreeBSD-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
-rw-r--r-- | sys/nfs/nfs_socket.c | 28 | ||||
-rw-r--r-- | sys/nfsclient/nfs_socket.c | 28 | ||||
-rw-r--r-- | sys/nfsserver/nfs_srvsock.c | 28 |
3 files changed, 72 insertions, 12 deletions
diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c index 0b314b1..0bf85c0 100644 --- a/sys/nfs/nfs_socket.c +++ b/sys/nfs/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. 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. diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c index 0b314b1..0bf85c0 100644 --- a/sys/nfsserver/nfs_srvsock.c +++ b/sys/nfsserver/nfs_srvsock.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. |