nfsd: fix a NFSv4.1 Linux client mount stuck in CLOSE_WAIT

It was reported that a NFSv4.1 Linux client mount against
a FreeBSD12 server was hung, with the TCP connection in
CLOSE_WAIT state on the server.
When a NFSv4.1/4.2 mount is done and the back channel is
bound to the TCP connection, the soclose() is delayed until
a new TCP connection is bound to the back channel, due to
a reference count being held on the SVCXPRT structure in
the krpc for the socket. Without the soclose() call, the socket
will remain in CLOSE_WAIT and this somehow caused the Linux
client to hang.

This patch adds calls to soshutdown(.., SHUT_WR) that
are performed when the server side krpc sees that the
socket is no longer usable.  Since this can be done
before the back channel is bound to a new TCP connection,
it allows the TCP connection to proceed to CLOSED state.

PR:	254590
Reported by:	jbreitman@tildenparkcapital.com
Reviewed by:	tuexen
Comments by:	kevans
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D29526
This commit is contained in:
Rick Macklem 2021-04-27 15:32:35 -07:00
parent eea55de7b1
commit db8c27f499

View File

@ -203,6 +203,8 @@ svcpool_cleanup(SVCPOOL *pool)
mtx_unlock(&grp->sg_lock);
}
TAILQ_FOREACH_SAFE(xprt, &cleanup, xp_link, nxprt) {
if (xprt->xp_socket != NULL)
soshutdown(xprt->xp_socket, SHUT_WR);
SVC_RELEASE(xprt);
}
@ -388,6 +390,8 @@ xprt_unregister(SVCXPRT *xprt)
xprt_unregister_locked(xprt);
mtx_unlock(&grp->sg_lock);
if (xprt->xp_socket != NULL)
soshutdown(xprt->xp_socket, SHUT_WR);
SVC_RELEASE(xprt);
}
@ -1078,6 +1082,7 @@ svc_checkidle(SVCGROUP *grp)
mtx_unlock(&grp->sg_lock);
TAILQ_FOREACH_SAFE(xprt, &cleanup, xp_link, nxprt) {
soshutdown(xprt->xp_socket, SHUT_WR);
SVC_RELEASE(xprt);
}
mtx_lock(&grp->sg_lock);