From owner-freebsd-bugs Mon Apr 5 17:12: 2 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id E3EEA153CB for ; Mon, 5 Apr 1999 17:11:58 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.2/8.9.2) id RAA91049; Mon, 5 Apr 1999 17:10:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from wrath.cs.utah.edu (wrath.cs.utah.edu [155.99.198.100]) by hub.freebsd.org (Postfix) with ESMTP id 50CDE1552E for ; Mon, 5 Apr 1999 17:10:44 -0700 (PDT) (envelope-from sclawson@cs.utah.edu) Received: from ibapah.cs.utah.edu (ibapah.cs.utah.edu [155.99.212.83]) by wrath.cs.utah.edu (8.8.8/8.8.8) with ESMTP id SAA27093 for ; Mon, 5 Apr 1999 18:08:46 -0600 (MDT) Received: (from sclawson@localhost) by ibapah.cs.utah.edu (8.9.1/8.9.1) id SAA19667; Mon, 5 Apr 1999 18:08:45 -0600 (MDT) (envelope-from sclawson@cs.utah.edu) Message-Id: <199904060008.SAA19667@ibapah.cs.utah.edu> Date: Mon, 5 Apr 1999 18:08:45 -0600 (MDT) From: Stephen Clawson Reply-To: sclawson@cs.utah.edu To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: bin/10970: Children of ypserv don't necessarily go away. Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 10970 >Category: bin >Synopsis: Children of ypserv don't necessarily go away. >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Apr 5 17:10:01 PDT 1999 >Closed-Date: >Last-Modified: >Originator: Stephen Clawson >Release: FreeBSD 3.0-CURRENT i386 (jan 27, 1999) >Organization: University of Utah Computer Science >Environment: We've set up a yp slave server on a dual Pentium II/350 to provide yp service to a group of twenty or so FreeBSD machines and a few assorted linux boxes. I actually noticed this bug while trying to track down why ypserv was segfaulting on us. =) The underlying network is switched 100BaseT to the server. >Description: There are only two places that ypserv forks: the yp_all handling code (ypproc_all_2_svc) and yp_xfr (ypproc_xfr_2_svc). In either case, the child sets a flag (forked) so that when it returns to the main loop it will exit. (code from yp_main.c:yp_svc_run): if (forked && pid != getpid()) _exit(0); The problem is that along with setting the flag in the child, it resets the flag in the parent! This causes problems, since you can potentially service multiple requests in the child, as evicenced by a backtrace I captured from a forked child (I added debugging code to stop the process so that I could attach to it if it entered pproc_all_2_svc again after it had finished): (gdb) bt #0 0x8049050 in ypproc_all_2_svc (argp=0xefbfc89c, rqstp=0xefbfcda4) at yp_server.c:527 #1 0x804862a in ypprog_2 (rqstp=0xefbfcda4, transp=0x8088140) at yp_svc.c:265 #2 0x804d54e in svc_getreqset2 (readfds=0x8086080, width=18) at /usr/src/lib/libc/../libc/rpc/svc.c:465 #3 0x804bd6e in readtcp (xprt=0x8088380, buf=0x80a6fa0 "\200", len=4000) at /usr/src/lib/libc/../libc/rpc/svc_tcp.c:351 #4 0x8059ccb in fill_input_buf (rstrm=0x808d500) at /usr/src/lib/libc/../libc/xdr/xdr_rec.c:511 #5 0x8059d0c in get_input_bytes (rstrm=0x808d500, addr=0xefbfce90 "\005\b/libc/xdr/xdr_rec.c:212 #9 0x805d05c in xdr_u_int32_t (xdrs=0x809d808, u_int32_p=0xefbfd430) at /usr/src/lib/libc/../libc/xdr/xdr.c:242 #10 0x804d8fd in xdr_callmsg (xdrs=0x809d808, cmsg=0xefbfd430) at /usr/src/lib/libc/../libc/rpc/rpc_callmsg.c:180 #11 0x804bed6 in svctcp_recv (xprt=0x8088380, msg=0xefbfd430) at /usr/src/lib/libc/../libc/rpc/svc_tcp.c:421 #12 0x804d472 in svc_getreqset2 (readfds=0xefbfd494, width=1024) at /usr/src/lib/libc/../libc/rpc/svc.c:442 #13 0x804d3c8 in svc_getreqset (readfds=0xefbfd494) at /usr/src/lib/libc/../libc/rpc/svc.c:408 #14 0x804ae10 in yp_svc_run () at yp_main.c:146 #15 0x804b2b4 in main (argc=1, argv=0xefbfd570) at yp_main.c:339 #16 0x80480ca in _start () This shouldn't be a suprise, since according to the man page, svc_getreqset() "returns when all sockets associated with the value of rdfds have been serviced." When the child goes through the second time it's now a parent and so it's forked flag is reset! Thus when it does eventually return it dosen't go away. =( >How-To-Repeat: Since calling yp_all is the only procedure that will cause this problem, it's pretty easy to reproduce. Set up a yp server and barrage it with as many yp_all requests that you can. The simplest way to do this is to fork off a bunch of `ypcat passwd' processes from a client machine (20 is usually sufficent). You've got to get enough going at a time that a forked child will respond to two or more. >Fix: Assuming that it's reasonable to have a forked child respond to multiple requests(*), then the simplest thing to do is to get rid of the code that resets `forked' in the parent process. We'll also want to make sure that the child dosen't fork again, since it's stupid to fork off another process to handle a request when you're just going to return and exit... It also screws up the code that's trying to limit the maximum number of children if child processes can fork. =) The pid gunk and the change from exit(0) to _exit(0) should also go away, since they seem to be trying to fix the same problem, but don't make any sense from what I can tell. (*) In OpenBSD's version of ypserv, the child that handled yp_all just exits after it's done instead of returning. This also takes care of the problem. Index: yp_main.c =================================================================== RCS file: /n/marker/usr/lsrc/FreeBSD/CVS/src/usr.sbin/ypserv/yp_main.c,v retrieving revision 1.19 diff -c -r1.19 yp_main.c *** yp_main.c 1999/02/10 16:16:14 1.19 --- yp_main.c 1999/04/03 00:28:27 *************** *** 108,120 **** int readfds; #endif /* def FD_SETSIZE */ extern int forked; - int pid; int fd_setsize = _rpc_dtablesize(); struct timeval timeout; - /* Establish the identity of the parent ypserv process. */ - pid = getpid(); - for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; --- 108,116 ---- *************** *** 144,151 **** } svc_getreqset(&readfds); } ! if (forked && pid != getpid()) ! _exit(0); } } --- 140,147 ---- } svc_getreqset(&readfds); } ! if (forked) ! exit(0); } } Index: yp_server.c =================================================================== RCS file: /n/marker/usr/lsrc/FreeBSD/CVS/src/usr.sbin/ypserv/yp_server.c,v retrieving revision 1.27 diff -c -r1.27 yp_server.c *** yp_server.c 1999/02/10 16:16:14 1.27 --- yp_server.c 1999/04/03 00:25:38 *************** *** 392,398 **** default: result.xfrstat = YPXFR_SUCC; children++; - forked = 0; break; } --- 392,397 ---- *************** *** 506,512 **** * block. (Is there a better way to do this? Maybe with * async socket I/O?) */ ! if (!debug) { switch(fork()) { case 0: forked++; --- 505,511 ---- * block. (Is there a better way to do this? Maybe with * async socket I/O?) */ ! if (!forked && !debug) { switch(fork()) { case 0: forked++; *************** *** 518,524 **** break; default: children++; - forked = 0; return (NULL); break; } --- 517,522 ---- To: FreeBSD-gnats-submit@freebsd.org Subject: From: sclawson Reply-To: sclawson X-send-pr-version: 3.2 >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message