Thread View: comp.bugs.2bsd
4 messages
4 total messages
Started by Steven M. Schultz(Y)
Thu, 29 Jun 1989 06:22
TIME_WAIT sockets clog system (part 2)
Author: Steven M. Schultz(Y)
Date: Thu, 29 Jun 1989 06:22
Date: Thu, 29 Jun 1989 06:22
72 lines
2912 bytes
2912 bytes
Subject: TIME_WAIT sockets clog system (part 2)
Index: sys/sys/uipc_mbuf.c 2.10BSD
Description:
Sockets in a TIME_WAIT state can constipate the networking
buffer memory when generated in rapid succession by, for
example, an "mget" in an ftp session. If more than a dozen
or so small files are transferred in rapid succession over
an ethernet, all the mbufs in the system will be taken up
by sockets in a TIME_WAIT state (from the socket opened for
each data transfer).
Repeat-By:
ftp in to a 2.10.1BSD system, do an "mget *" in a largish
directory. note that the transfer will hang/develope problems
after about a dozen to twenty files. the 2.10.1BSD system
has run out of mbufs and will recover in a minute or so (hopefully).
It should be noted that even a Vax could be run out of mbufs
if the directory were large enough and network memory was full
due to other causes.
Fix:
Apply this patch to /sys/sys/uipc_mbuf.c. The effect of this fix
is to call the drain routines at least once - the earlier version
of m_more() checked the waitability state and rejected the
request immediately rather than attempt non-blocking methods
of freeing up memory first.
It is (as far as i can see - and yes, these fixes have been tested)
safe to call the drain routines at this point for two reasons:
1) the tcp_drain() routine that existed prior to part 1 of this
fix did nothing AND the NEW tcp_drain() routine is guaranteed not
to sleep(), 2) the ip_drain() routine only releases fragments and
does not sleep() at any point along the way.
With both part 1 and 2 installed a "ftp mget *" of /etc was done
with no problems and 8 calls to the drain routines (as reported
by 'netstat -s').
*** uipc_mbuf.old Tue Jun 27 23:20:46 1989
--- uipc_mbuf.c Tue Jun 27 23:23:14 1989
***************
*** 164,177 ****
{
register struct mbuf *m;
- if (canwait == M_DONTWAIT) {
- mbstat.m_drops++;
- return (NULL);
- }
for(;;) {
m_expand(canwait);
if (mfree)
break;
mbstat.m_wait++;
m_want++;
SLEEP((caddr_t)&mfree, PZERO - 1);
--- 164,177 ----
{
register struct mbuf *m;
for(;;) {
m_expand(canwait);
if (mfree)
break;
+ if (canwait == M_DONTWAIT) {
+ mbstat.m_drops++;
+ return (NULL);
+ }
mbstat.m_wait++;
m_want++;
SLEEP((caddr_t)&mfree, PZERO - 1);
Re: TIME_WAIT sockets clog system (part 2)
Author: Dan Lanciani
Date: Fri, 30 Jun 1989 16:27
Date: Fri, 30 Jun 1989 16:27
40 lines
2756 bytes
2756 bytes
There is a potential problem with the proposed modifications to the mbuf allocator. The "cantwait" argument to the allocation routines is more than just an indication of whether it is ok to sleep. It is also a subtle hint that the routine was not called from a (potentially plimp) interrupt routine. If an allocation routine is called from, e.g., the ethernet interrupt it would be incorrect to (re)enter the network at plnet because (1) the network code may inadvertently lower the pl and (2) the network code may itself have been interrupted at a critical section. Unfortunately, to be useful, most *_drain routines must ultimately access global structures which are protected only by splnet's and thus are eventually likely to cause corruption. It may be possible to check the current pl on entry to the allocator (tricky because of the macros) and distinguish three classes of request (from least to most restrictive): task-time (may sleep and/or call the network), interrupt-time where previous pl was less than plnet (may call the network), and interrupt-time where previous pl was plnet or higher. Of course, since you cannot find the true previous pl, you would have to assume that the current pl is higher than the previous and work from there. This scheme breaks down if any plnet code calls the allocator in the expectation that it won't reenter, but such cases could be fixed. There is a somewhat different approach to the mbuf problem which might also be helpful. History: The allocator in 2.9 ignored the "cantwait" argument--it never slept at all. Needless to say, problems arose frequently. My first attempt to improve the situation was to add appropriate sleeps, making the system run much the way 4.3 does now, i.e., top-level code can wait for mbufs but most other code can't. This helped very little. Typically, a send call would block in the allocator until an mbuf became available and then call the tcp send routine which would promptly request an mbuf "DONTWAIT" and fail. The solution was to make allocation requests which *could* wait *always* wait until some fraction (say, 50%) of mbufs were free. This is effect reserved half of the mbufs for code that couldn't wait and improved matters significantly. Dan Lanciani ddl@harvard.*
Re: TIME_WAIT sockets clog system (part 2)
Author: Steven M. Schultz(Y)
Date: Fri, 30 Jun 1989 23:30
Date: Fri, 30 Jun 1989 23:30
53 lines
2910 bytes
2910 bytes
In article <2144@husc6.harvard.edu> ddl@husc6.harvard.edu (Dan Lanciani) writes: > There is a potential problem with the proposed modifications >to the mbuf allocator. The "cantwait" argument to the allocation >routines is more than just an indication of whether it is ok to sleep. >It is also a subtle hint that the routine was not called from a >(potentially plimp) interrupt routine. If an allocation routine >is called from, e.g., the ethernet interrupt it would be incorrect >to (re)enter the network at plnet because (1) the network code may >inadvertently lower the pl and (2) the network code may itself have >been interrupted at a critical section. > Unfortunately, to be useful, most *_drain routines must >ultimately access global structures which are protected only by >splnet's and thus are eventually likely to cause corruption. Thanks for the hints/warning. i'd like to "explore"/"discuss" this a bit. Inadvertent lowering of the priority is the bugaboo to be afraid of as i understand it, the consequences of recursive interrupts, etc are well known to me (i only blew it twice in getting if_ec.c working for 2.10.1BSD). The m_more() routine is required to be called at splimp(), not splnet(). The m_expand() routine which is called by m_more() also is required to be called at splimp(). The tcp_drain() routine i proposed (actually i'm running it as i type) raises spl to splimp() out of paranoia. Besides which, the *_drain routines are only called from m_expand() which is at splimp already. Last i looked, splimp() is higher than splnet() so there is not any inadvertent lowering of priority. Yes, if in the future, the *_drain routines get "smarter" or more complicated, then problems probably will arise. Given the current setup everything seems in order. What have i missed? Please be kind - it was late when i "had to do something about the ftp mget" problem ;-) >The solution was to make allocation requests which >*could* wait *always* wait until some fraction (say, 50%) of >mbufs were free. This is effect reserved half of the mbufs >for code that couldn't wait and improved matters significantly. Hmmmm, that sounds interesting! Might be worth a shot. Thanks! Steven M. Schultz sms@wlv.imsd.contel.com
Re: TIME_WAIT sockets clog system (part 2)
Author: Dan Lanciani
Date: Sun, 02 Jul 1989 01:08
Date: Sun, 02 Jul 1989 01:08
58 lines
3182 bytes
3182 bytes
In article <33315@wlbr.IMSD.CONTEL.COM>, sms@WLV.IMSD.CONTEL.COM (Steven M. Schultz(Y)) writes: | Inadvertent lowering of the priority is the bugaboo to be | afraid of as i understand it, the consequences of recursive | interrupts, etc are well known to me (i only blew it twice in | getting if_ec.c working for 2.10.1BSD). This is no more or less to be feared than corruption of global data structures. | The m_more() routine is required to be called at splimp(), not splnet(). | | The m_expand() routine which is called by m_more() also is required | to be called at splimp(). This is done so that the allocator can be called from plimp interrupt routines. The mbuf allocator is one of the few pieces of the network that may be called by such routines. Another is the arpinput code, but that's easy to get rid of and I digress... | The tcp_drain() routine i proposed (actually i'm running it as i type) | raises spl to splimp() out of paranoia. Besides which, the *_drain | routines are only called from m_expand() which is at splimp already. This piece of paranoia both does no good and is misleading. It protects your tcp_drain routine from being interrupted, but this isn't the problem. The problem is that your tcp_drain routine can be *called* from a plimp interrupt routine. In any case, the problem is not with tcp_drain, but with the modification to the memory allocator. | Last i looked, splimp() is higher than splnet() so there is not | any inadvertent lowering of priority. But your tcp_drain does not stand by itself. It calls tcp_close. Tcp_close calls (among other things) in_pcbdetach. In_pcbdetach access the linked list of protocol control blocks. It also calls sofree. | Yes, if in the future, the *_drain routines get "smarter" or more | complicated, then problems probably will arise. Given the current | setup everything seems in order. You can't get much more complicated than calling the tcp_close function... | What have i missed? Please be kind - it was late when i "had to | do something about the ftp mget" problem ;-) From the structure of your loop in tcp_drain, you obviously noticed that tcp_close will delete protocol control blocks from the tcb chain. How would you feel if you were a happy little plnet routine walking the tcb chain and then the tcp_drain routine was called by the ethernet interrupt's asking for an mbuf, thus invalidating your pointer? For a more definite example, consider the tcp_fasttimo routine and think about what would happen if you deleted the protocol control block that it was currently looking at. Dan Lanciani ddl@harvard.*
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads