On Wed, Jan 10, 2024 at 03:10:55PM +0100, Alexandre Ratchov wrote:
> 
> After 5 minutes with no requests (below), the client tries to close
> the connection. OpenBSD doesn't seem to reply with a fin packet. At
> this point the client freezes until the file system is umounted. New
> requests generate no network traffic. Probably, the NFS client waits
> for the connection to be fully closed because it needs to reconnect
> with the same source port.
> 
> 13:08:07.016331 10.0.0.43.942 > 10.0.0.8.2049: F 477:477(0) ack 509 win 249 
> <nop,nop,timestamp 669017420 1556476115> (DF)
> 13:08:07.016348 10.0.0.8.2049 > 10.0.0.43.942: . ack 478 win 1030 
> <nop,nop,timestamp 1556532435 669017420> (DF)
> 13:08:12.056350 arp who-has 10.0.0.8 tell 10.0.0.43
> 13:08:12.056355 arp reply 10.0.0.8 is-at fe:e1:ba:d0:b3:80
> 13:09:08.456989 10.0.0.43.942 > 10.0.0.8.2049: . ack 509 win 249 
> <nop,nop,timestamp 669078860 1556532435> (DF)
> 13:09:08.457006 10.0.0.8.2049 > 10.0.0.43.942: . ack 478 win 1030 
> <nop,nop,timestamp 1556593875 669078860> (DF)
> 13:09:13.497038 arp who-has 10.0.0.8 tell 10.0.0.43
> 13:09:13.497049 arp reply 10.0.0.8 is-at fe:e1:ba:d0:b3:80
> 

Here's what seems to happen (thanks Claudio for the hints):

The server detects that the connection is closed. It doesn't close the
socket immediately and starts waiting for the client to reconnect (or
another client, etc). As the socket is not closed, from client's point
of view, the connection is still not fully closaed, so it keeps
waiting before reconnecting with the same source port; a kind of
deadlock.

The diff below fixes this by checking for EOF before sleeping.

OK?

Index: nfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/nfs/nfs_syscalls.c,v
diff -u -p -r1.119 nfs_syscalls.c
--- nfs_syscalls.c      3 Aug 2023 09:49:09 -0000       1.119
+++ nfs_syscalls.c      11 Jan 2024 15:15:12 -0000
@@ -338,6 +338,15 @@ loop:
                                nfs_sndlock(&slp->ns_solock, NULL);
                                nfsrv_rcv(slp->ns_so, (caddr_t)slp, M_WAIT);
                                nfs_sndunlock(&slp->ns_solock);
+
+                               /*
+                                * The client may have closed the connection.
+                                * If so, zap the socket before sleeping,
+                                * allowing the client to reconnect with the
+                                * same source port.
+                                */
+                               if (ISSET(slp->ns_flag, SLP_DISCONN))
+                                       nfsrv_zapsock(slp);
                        }
 
                        error = nfsrv_dorec(slp, nfsd, &nd);

Reply via email to