[news.software.nntp] Too-many-open-files bug in NNTP 1.5.10 server fixed

net@tub.UUCP (Oliver Laumann) (10/15/90)

I think I've found the bug that causes the NNTP 1.5.10 server to get
into a mode where it prints "spawn: pipe: Too many open files" for every
incoming article.

The culprit is the call to vfork() followed by a call to closelog() in
the child process in server/spawn.c.  closelog() not only closes the
file descriptor used by syslog(), but also sets (or clears; I don't have
the sources) a variable shared between closelog and syslog to indicate
that the socket must be re-opened in the next call to syslog().

Since spawn.c uses vfork() instead of fork(), this variable is also
set or cleared in the parent process, so that the next call to syslog()
re-opens the socket, although it has only been closed in the child
process.  This is repeated until all available file descriptors are in use.

I don't know an easy fix for this other than replacing vfork by fork.

Regards,
--
Oliver Laumann     net@TUB.BITNET     net@tub.cs.tu-berlin.de     net@tub.UUCP

leres@ace.ee.lbl.gov (Craig Leres) (10/16/90)

Oliver Laumann writes:
> The culprit is the call to vfork() followed by a call to closelog() in
> the child process in server/spawn.c.  closelog() not only closes the
> file descriptor used by syslog(), but also sets (or clears; I don't have
> the sources) a variable shared between closelog and syslog to indicate
> that the socket must be re-opened in the next call to syslog().

Too true. Personally, I dislike code that closes all fd's after
forking. It tends to break things like syslog and yp and in fact the
closelog() code is my fix. I didn't have any problems with it since
we're a cnews site and enqueue() uses fork() instead of vfork().

Anyway, if we must keep the child close() loop, seems like the best
solution is to move the closelog() to before the vfork(). This way both
the parent and the child will know to reopen the fd. And since most
openlog's()'s delay the syslog socket open until the first actual
syslog(), this shouldn't be too expensive.

Experimental context diff for the adventurous follows.

		Craig
------
RCS file: RCS/spawn.c,v
retrieving revision 1.10
diff -c -r1.10 spawn.c
*** /tmp/,RCSt1a14422	Mon Oct 15 21:25:25 1990
--- spawn.c	Mon Oct 15 21:23:48 1990
***************
*** 164,169 ****
--- 164,178 ----
  	 * whatever), open "tempfile" for input, thus making
  	 * it stdin, and then execle the inews.  We think.
  	 */
+ #ifdef SYSLOG
+ 	/*
+ 	 * Close in such a way that syslog() will know to reopen.
+ 	 * We must do this before the vfork() otherwise the parent
+ 	 * will think the syslog fd is closed and open a new one,
+ 	 * eventually using up all the available file descriptors.
+ 	 */
+ 	closelog();
+ #endif
  
  	pid = vfork();
  	if (pid == 0) {		/* We're in child */
***************
*** 183,192 ****
  		}
  		(void) dup2(1, 2);
  
- #ifdef SYSLOG
- 		/* Close in such a way that syslog() will know to reopen */
- 		closelog();
- #endif
  		for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */
  			(void) close(i);
  
--- 192,197 ----