Subject: Fun with Limits
To: None <tech-kern@netbsd.org>
From: None <eeh@netbsd.org>
List: tech-kern
Date: 02/08/2001 18:40:32
I have some issues with the current handling of limits.

What we do now is have a set of maximum allowable values
for the sizes of the text, data, and stack segments.  
These values are defined in `machine/vmparam.h' and 
used to initialize proc0's hard limits, which are then
inherited by all other processes.

Most machines set surprizingly low hard limits.  Alpha, 
for instance, limits text and data sizes to 1GB, and 
the stack to 32MB.  This limits the maximum process 
size to barely over 2GB.  SPARC is limited to 64MB 
text and 256MB data and stack.  i386 has 64MB text, 1GB 
data, and 32MB stack.

Why are these limits so low?  These values are not only 
used to limit the maximum size of a process.  These 
constants are also are used to construct a process' 
address space on exec, which is where problems arise.

When a process image is exec'ed, it's address space 
is constructed based, not on the current soft limits, 
nor the current hard limits, but those constants.  
So if that architecture allows 1GB for the stack 
size, 1GB of address space is reserved for the stack, 
even if the limits currently allow for only 2MB.

If your machine runs both 32-bit and 64-bit processes, 
this is a problem.  If you set the limits for 32-bit
processes, 64-bit processes are limited to well under
2GB of data.  If you set the limits for 64-bit processes,
you cannot exec 32-bit processes because there isn't
enough address space in 32-bits to reserve for those
limits.  If you allow, for example, a maximum stack
size of 4GB, which on a 64-bit machine is less than
1 billionth of a process' address space, you cannot 
execute a 32-bit process since there is absolutely
nothing left for text or data.

I'm aware of three possible solutions to this problem:

1) Use limits for 32-bit address spaces for everything.
While this does solve the problem, it brings in to question
why the cost of 64-bit pointers is being payed at all.  If
you only use <32 bits of address space, you might as well
use 32-bit pointers so your programs are more compact and
have smaller cache footprints.

2) Use different limits for 32-bit and 64-bit processes.
Limits are inherited.  Things get complicated if a 64-bit
process execs a 32-bit process, which then execs a 64-bit 
process.  If you have two sets of limits and you increase
or decrease a 64-bit limit, what do you do with the 
corresponding 32-bit limit, or visa-versa?

3) Use the current soft limits to size the address space
and worry about hard limits or maximums when those limits
are being increased.  Since the soft limits are usually
small fractions of the current, or even default hard
limits, this solves the issue durning exec time, but
complicates the problem when changing limits.  What if
you try to increase your stack limit but something else
is already mapped there?

I prefer option three, but I thought I should throw it
out to tech-kern and see if it generates some discussion
before I start implementing things.

Eduardo