bin/75766: [patch] nfsd loops with TCP + multiple -h options
Mike Hibler
mike at flux.utah.edu
Mon Jan 3 21:40:21 GMT 2005
>Number: 75766
>Category: bin
>Synopsis: [patch] nfsd loops with TCP + multiple -h options
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Mon Jan 03 21:40:20 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Mike Hibler
>Release: FreeBSD 4.x
>Organization:
University of Utah
>Environment:
System: FreeBSD bas.flux.utah.edu 4.10-RELEASE-p5 FreeBSD 4.10-RELEASE-p5 #2: Thu Dec 30 16:50:05 MST 2004 root at bas.flux.utah.edu:/usr/obj/usr/src/sys/BAS i386
>Description:
Running nfsd with TCP support (-t) and multiple -h options can lead
to the nfsd master process spinning furiously.
In short, when the master nfsd process returns from a select involving
multiple fds, it only attempts to process the last fd rather than
looping over all fds in the set.
This bug exists in all 4.x versions as far as I know.
>How-To-Repeat:
Run nfsd with TCP support (-t) and multiple -h options and attempt
to connect via any network except that of the last interface listed
with -h.
>Fix:
Following is the minimal fix extracted from -CURRENT to fix the
problem; i.e., stick a loop around the FD_ISSET() processing.
Note that I did not bother to fix the "notyet" code.
--- nfsd.c 2005/01/03 20:37:09 1.1
+++ nfsd.c 2005/01/03 20:41:44
@@ -593,26 +593,29 @@
exit(1);
}
}
- if (tcpflag && FD_ISSET(tcpsock, &ready)) {
- len = sizeof(inetpeer);
- if ((msgsock = accept(tcpsock,
- (struct sockaddr *)&inetpeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- if (errno == ECONNABORTED ||
- errno == EINTR)
- continue;
- exit(1);
+ for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
+ if (FD_ISSET(tcpsock, &ready)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ if (errno == ECONNABORTED ||
+ errno == EINTR)
+ continue;
+ exit(1);
+ }
+ memset(inetpeer.sin_zero, 0,
+ sizeof(inetpeer.sin_zero));
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = sizeof(inetpeer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
}
- memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR,
- "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&inetpeer;
- nfsdargs.namelen = sizeof(inetpeer);
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
}
#ifdef notyet
if (tp4flag && FD_ISSET(tp4sock, &ready)) {
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list