Many applications, like Oracle 11g, need larger than default process values for things like stack size and file descriptors and normally document it in their installation guides. Oracle 11gR2 is very vague about how to configure the "shell limits" and instead concentrates on telling you what it expects and how you can check the current values using ulimit(1).

Update - 9 March 2012: This post has been updated to reflect a correction in behaviour introduced in patch 146654-01 (SPARC) and/or 146670-02 (SPARC) and 146655-01 (x86) and/or 146671-02 (x86). These patches fix a problem (CR 6911915) where "basic" and "privilege" /etc/project settings we not being set correctly and thus "privileged" /etc/project settings were showing as soft limits in ulimit(1).

Using ulimit(1)

Most sysadmins turn to using ulimit(1) to set the appropriate values by adding something like the following to the system-wide /etc/profile or the specific application user's profile (the comments are mine):

# Set stack size to unlimited
ulimit -s unlimited
# Set maximum file descriptors to unlimited
ulimit -n unlimited

For the curious, these are the defaults on a Solaris 10 8/11 system (which includes the above patches) using the zsh shell as it shows the ulimit(1) options:

$ ulimit -Sa
-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        8192
-c: core file size (blocks)    0
-n: file descriptors           256
-v: virtual memory size (kb)   unlimited
$
$ ulimit -Ha
-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        unlimited
-c: core file size (blocks)    0
-n: file descriptors           65536
-v: virtual memory size (kb)   unlimited

This is all well and good and works. There are however a few disadvantages with this approach:

  1. It adds another location to configure settings for your application which you may forget about.
  2. If placed in the /etc/profile, these limits will affect ALL users and processes on the system unless you add in various checks in your /etc/profile to try and limit the users this applies to.
  3. This is an antiquated method of setting these settings. Projects are the way to go. You're already using projects to set the semaphore and shared memory settings (here in the Oracle 11gR2 docs), so why not use this same functionality for setting these shell limits?

Using Projects

So how do you do it in projects?

Each of these ulimit(1) options equates to a corresponding project control:

ulimit(1) option and explanation Projects Control Name
-t: cpu time (seconds) process.max-cpu-time
-f: file size (blocks) process.max-file-size
-d: data seg size (kbytes) process.max-data-size
-s: stack size (kbytes) process.max-stack-size
-c: core file size (blocks) process.max-core-size
-n: file descriptors process.max-file-descriptor
-v: virtual memory size (kb) process.max-address-space

So it's just a matter of running the appropriate projmod(1) command to set the desired value.

For example to set the stack size to 32768 kb use:

# projmod -s -K "process.max-stack-size=(privileged,32MB,deny)" user.oracle

To set the file descriptors to 1024 use:

# projmod -s -K "process.max-file-descriptor=(privileged,1024,deny)" user.oracle

Or set both at the same time using:

# projmod -s -K "process.max-stack-size=(privileged,32768kb,deny);process.max-file-descriptor=(privileged,1024,deny)" user.oracle

Note: If you don't already have a user.oracle project, you'll need to use projadd(1M). See its man page for usage details. You can also use "friendly" values as I have done above.

Keep in mind that "basic" /etc/project settings equate to soft limits within ulimit(1) and "privileged" /etc/project settings equate to hard limits within ulimit(1). ulimit(1)'s default output is also to display the soft limits.

Your changes will only take effect on new processes created by that user, except those created as children of processes that were started before you made the change. If you can't stop a process you can use newtask(1) to assign the running process a new task, or use prctl(1) to change these values on running processes. See the respective man pages for details on how to do this.

You can verify your changes have taken effect using ulimit(1), run as the oracle user in a new shell started after the project modifications:

$ ulimit -Ha
-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        32768
-c: core file size (blocks)    0
-n: file descriptors           1024
-v: virtual memory size (kb)   unlimited
$

... or prctl(1) run as the oracle user in a new shell started after the project modifications...


$ prctl -n process.max-stack-size -t privileged  $$
process: 13152: zsh
NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-stack-size
        privileged      32.0MB      -   deny                                 -
$ prctl -n process.max-file-descriptor -t privileged  $$
process: 13152: zsh
NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-file-descriptor
        privileged      1.02K       -   deny                                 -
$

Note, the soft limits will not have changed as we set our settings using the "privileged" type:

$ ulimit -Sa
-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        8192
-c: core file size (blocks)    0
-n: file descriptors           256
-v: virtual memory size (kb)   unlimited
$
$ prctl -n process.max-stack-size -t basic  $$
process: 13152: -zsh
NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-stack-size
        basic           8.00MB      -   deny                             13152
$ prctl -n process.max-file-descriptor -t basic  $$
process: 13152: -zsh
NAME    PRIVILEGE       VALUE    FLAG   ACTION                       RECIPIENT
process.max-file-descriptor
        basic             256       -   deny                             13152
$

If you set "basic" /etc/project settings, the "privileged" and thus hard limits will not change.

Setting Unlimited

One question that often comes up is...

How do I set one of these values to 'unlimited' via projects like I can using ulimit?

This isn't actually made very clear in the Resource Management documentation. You can't use the word "unlimited" as the resource controls have no concept of "unlimited". Instead, you just need to set the value to the maximum allowed system value.

So what is the maximum allowed system value? Well you could dig out the tunable parameters guide and trawl through it, but the easiest method is to use prctl(1) to query the "system" value for the appropriate resource control for your current shell.

For example, to see the maximum stack size, use:

$ prctl -P -t system -n process.max-stack-size $$
process: 13152: zsh
process.max-stack-size system 9223372036854775807 max deny -
$

You can then use this value in your projmod(1) command...

# projmod -s -K "process.max-stack-size=(privileged,9223372036854775807,deny)" user.oracle

... and then verify it as the oracle user...

# su - oracle -c "ulimit -Hs"
Oracle Corporation	SunOS 5.10	Generic Patch	January 2005
unlimited
#

You can find further details on using projects for resource management in the Resource Management section of the System Administration Guide: Oracle Solaris Containers-Resource Management and Oracle Solaris Zones guide.