No system has a limitless supply of resources. Because of this, Linux provides means to restrict their use.
In this tutorial, we explore one method to limit the system resource usage and discuss its associated concepts. First, we dive deep into the main Linux command to restrict resource allocation. After that, we discuss the types of limits we can use.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
Indeed, the ulimit tool can get or set the upper bounds for different resources such as:
- -f, size of files the shell and its processes can write (1024-byte increments)
- -n, number of open file descriptors (no unit)
- -p, pipe buffer size (512-byte increments)
- -u, number of user processes (no unit)
- -T, number of threads (no unit)
Importantly, not all resources in a given system or (user) context may be available via ulimit. Let’s get a report on the ones we can control:
$ ulimit -a real-time non-blocking time (microseconds, -R) unlimited core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 [...]
Here, the -a switch reports every resource type on a separate line with its unit and flag in parentheses.
2.1. Checking and Getting Limits
Without an argument, ulimit returns the limit for the -f flag by default:
$ whoami user1 $ ulimit unlimited
First, we confirm our user as user1 with the whoami command. Next, we see that this user is not limited in terms of the filesize they can write in the shell and its child processes.
To get a specific resource setting, we supply its flag alone:
$ ulimit -c 0
Here, 0 means there is no limit to the core file size (-c).
2.2. Setting Limits
Finally, we can set a limit by supplying it directly after the resource flag:
$ ulimit -p 8 $ ulimit -p 1 $ ulimit -p 1
In this example, after confirming its initial value as 8, we set a limit of 1 (times 1024 bytes) as the limit for the pipe buffer size. Checking back with ulimit -p confirms it’s modified as expected.
Importantly, the pam_limits.so pluggable authentication module (PAM) and its main configuration file /etc/security/limits.conf are responsible for enforcing any limits. Moreover, the directory /etc/security/limits.d/ can also contain secondary files, which the PAM parses.
The basic syntax of the main and secondary files has four fields:
- <domain>: username, @group, or wildcard (* for default or %)
- <type>: hard, soft, or – (both)
- <item>: resource type, depending on the list ulimit -a or in the main configuration file comments
- <value>: resource limit value
Notably, setting limits for root does not work with wildcards.
To specify the type with ulimit, we use -H (hard) and -S (soft). Let’s explore what these types mean.
3. Hard and Soft Limits
In the context of resource usage limits, there are two categories: hard and soft. When it comes to ulimit, -H sets hard limits, while -S sets soft limits. By default, without either flag, -S is presumed.
3.1. Hard Limit
Hard limits are changeable only by superusers. Consequently, the kernel enforces them. This means that no user can use or set resources above such a limit. Going above this limit is globally forbidden by the kernel.
Let’s set a hard limit with ulimit as a superuser:
# ulimit -H -f unlimited # ulimit -H -f 1024 # ulimit -H -f 1024
Here, we confirmed the initial hard limit (-H) of the writable file size (-f) is unlimited. After that, we set it to 1024 and verify the new value. To understand how this restricts users, let’s explore the other limit type.
3.2. Soft Limit
Soft limits can be changed by the user as well. However, their upper bound is regulated by the corresponding hard limits. Still, a soft limit can be overstepped.
Let’s check both the hard and soft limits for a given resource with ulimit as user1:
$ ulimit -S -u 25316 $ ulimit -u 25316 $ ulimit -H -u 25316
Currently, both limit types on the maximum number of user processes (-u) are 25316.
Now, let’s attempt to raise the soft limit above the hard limit:
$ ulimit -S -u 25316 $ ulimit -S -u 25317 -bash: ulimit: max user processes: cannot modify limit: Invalid argument
Our attempt failed due to the restriction imposed by the hard limit. To raise the soft limit above 25316, we’d have to increase the hard limit.
However, we can always lower the soft limit for our particular user:
$ ulimit -S -u 19000 $ ulimit -S -u 19000
Naturally, setting our maximums too low might impair the system.
In this article, we talked about soft and hard limits in the context of resource usage restrictions.
In conclusion, Linux provides a straightforward mechanism for setting both soft and hard limits and enforcing them in different settings.