1. Introduction

In Linux system administration, effectively managing storage, i.e., disk space, is crucial, especially in shared environments where multiple users or groups coexist. To ensure fair resource allocation and prevent one user or group from monopolizing disk space, setting limits on directory sizes through disk quotas can be essential.

In this tutorial, we’ll explore the process of creating a simulated filesystem in a file, imposing directory size restrictions, and enforcing those limits using quotas.

2. Creating Directories and Files

First, we create a directory that will serve as the point where we access and manage the virtual filesystem we’ll create.

So, let’s make an empty directory via mkdir:

$ mkdir /point

To provide storage for our new virtual filesystem, we’ll create a file filled with zeros. This file will have a maximum size we want to reserve for the virtual filesystem.

Now, we’ll use dd to create the file:

$ dd if=/dev/zero of=~/mydatafile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.39109 s, 772 MB/s

Let’s break down this example:

  • if=/dev/zero reads from the /dev/zero special file, which provides an endless stream of null (zero) bytes
  • of=~/mydatafile writes the output to a file named mydatafile in the home directory
  • bs=1M sets the block size to one megabyte
  • count=1024 sets the number of blocks to copy, creating a 1GB file (1024 times one megabyte)

Furthermore, the output provides information about the number of data blocks processed, the amount of data transferred, the time taken, and the speed of the operation when creating the file.

3. Creating a Virtual Filesystem

Next, let’s format the mydatafile with an ext4 filesystem, effectively turning it into a virtual disk within a file:

$ mkfs.ext4 ~/mydatafile
mke2fs 1.46.5 (30-Dec-2021)
Discarding device blocks: done                            
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: fc801409-d5ee-488d-a7d9-2ea6a5c3f13c
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

Here, the output shows the various stages of creating an ext4 filesystem on the specified file ~/mydatafile and provides information about the filesystem’s characteristics and metadata.

Then, we’ll mount the virtual filesystem we just created to the mount point directory using mount with the loopback option:

$ sudo mount -o loop,rw,usrquota,grpquota ~/mydatafile /point

Here, we used -o to include the following options:

  • loop treats mydatafile as a loopback device, enables mount like a regular block device or disk partition
  • rw filesystem should be mounted in read-write mode, enabling both reading from and writing to it
  • usrquota, grpquota enable user and group quotas on the mounted filesystem

At this point, we have a virtual filesystem mounted in the specified directory with size limits.

After mounting, we can check the contents of /point via ls:

$ ls /point

As we can see, a lost+found directory has been created. It’s a repository for orphaned or recovered data resulting from filesystem issues, facilitating data recovery and repair operations. Moreover, the existence of this directory serves as a safeguard for preserving potentially lost or corrupted files.

Now, to make these settings persistent after a reboot, we can create an entry in the /etc/fstab:

$ cat /etc/fstab
/home/amir/mydatafile /point ext4 loop,rw,usrquota,grpquota 0 0

In this case, we specify that the filesystem within mydatafile should be mounted at the directory /point as ext4. The first zero indicates that the filesystem shouldn’t be automatically checked during boot. Next, the second zero means that the filesystem shouldn’t be included in automatic backup operations.

4. Adding User and Group Quotas

Now, we’ll set disk space limits on a directory for specific users or groups within the filesystem.

4.1. Prepare Environment

Firstly, we install quota via apt-get with sudo privileges:

$ sudo apt-get install quota

Secondly, we create a group for the quota:

$ sudo groupadd grpQuota

Thirdly, we assign the desired user to this group:

$ sudo usermod -G grpQuota amir

Then, we create a directory in the new filesystem we mounted and set the access rights via a recursive chown operation:

$ sudo mkdir /point/share
$ sudo chown -R root.grpQuota /point/share

Here, we created a directory named share, then set root as the owner and grpQuota as the owner group.

4.2. Initialize Quota Mechanism

At this point, we check and initialize disk quotas:

$ sudo quotacheck -cug /point

In this instance, we initialize and create the necessary database files for implementing disk quotas over /point. The -c option generates the initial quota database files, and -u checks and initializes user quotas. Lastly, -g checks and initializes group quotas.

At this point, we can list /point:

$ ls -l /point
total 36
-rw------- 1 root root      7168 Sep 22 13:56 aquota.group
-rw------- 1 root root      7168 Sep 22 15:37 aquota.user
drwx------ 2 root root     16384 Sep 22 11:00 lost+found
drwxr-xr-x 2 root grpQuota  4096 Sep 22 13:49 share

As we can see, two files, aquota.group and aquota.user, have been created in the /point path.

5. Set User Quotas

Initially, we set disk quotas for the user name via edquota:

$ sudo edquota -f /point amir

In this case, we used -f to specify the filesystem, while amir is the username.

Consequently, our default editor opens with the contents of the default quota settings:

Disk quotas for user amir (uid 1000):
 Filesystem                   blocks       soft       hard     inodes     soft     hard
 /dev/loop8                        0          0          0          0        0        0

Using the editor, we can change these settings:

Disk quotas for user amir (uid 1000):
 Filesystem                   blocks       soft       hard     inodes     soft     hard
 /dev/loop8                        0     500000     600000          0      90       100

In this case, the numbers represent soft and hard limits and are used to control the amount of disk space and the number of inodes (data structures that represent files and directories) that the user is allowed to use.

To demonstrate, let’s look at the quota limits:

  • soft block 500,000: the user uses up to roughly 500MB (500,000 KB) of disk space with a warning issued when reaching that limit
  • hard block 600,000: absolute maximum amount of disk space (roughly 600MB) that the user is allowed to use on this filesystem
  • soft inode 90: the user can create up to 90 files or directories without receiving warnings
  • hard inode 100: exact maximum number of inodes that the user can create files or directories

Notably, the numbers under blocks and inodes that indicate the current usage cannot be edited, as they’re read-only, and provided just as reference. These numbers ensure that the user doesn’t consume excessive disk space or create an excessive number of files and directories on the specified filesystem.

Alternatively, we can use the setquota command for this operation:

$ setquota -u amir 500000 600000 90 100 -a /dev/loop8

Now, we can turn the quota on:

$ sudo quotaon /point

Here, we used quotaon to activate disk quotas on the specific filesystem.

6. Set Group Quotas

We set group quotas similar to user quotas.

In essence, we first set the quota values for the group:

$ sudo edquota -g grpQuota

Just like before, we edit the settings file:

Disk quotas for group grpQuota (gid 1001):
 Filesystem                   blocks       soft       hard     inodes     soft     hard
 /dev/loop8                      4       700000     800000         1       380      400

Alternatively, we can use setquota:

$ sudo setquota -g grpQuota 700000 800000 380 400 -a /dev/loop8

Now, let’s break down this group quota limits:

  • soft block 700000: the group can collectively use up to roughly 700MB of disk space
  • hard block 800000: absolute maximum amount of disk space the group can use
  • soft inode 380: maximum number of files and directories that the group can create on the filesystem
  • hard inode 400: strict maximum number of files and directories that the group can create on the filesystem

Overall, these quotas help ensure that the group grpQuota doesn’t exceed the specified resource limits on this filesystem.

7. Reporting

repquota displays information about user and group quotas on filesystems. Thus, this enables system administrators to monitor and manage resource usage effectively.

So, let’s use repquota to show reports:

$ sudo repquota -ug /point
*** Report for user quotas on device /dev/loop8
Block grace time: 7days; Inode grace time: 7days
                        Block limits                File limits
User            used    soft    hard  grace    used  soft  hard  grace
root      --      24       0       0              3     0     0       
amir      --      24  500000  600000              3   90    100       

*** Report for group quotas on device /dev/loop8
Block grace time: 7days; Inode grace time: 7days
                        Block limits                File limits
Group           used    soft    hard  grace    used  soft  hard  grace
root      --      20       0       0              2     0     0       
grpQuota  --       4  700000  800000              1   380   400 

The output displays disk quota information for users and groups on the filesystem. It includes details like the amount of disk space used (blocks), the soft quota limit, the hard quota limit, and the number of inodes (file entries) used.

8. Conclusion

In this article, we’ve explored the essential practice of implementing directory size limits with disk quotas in Linux to maintain fairness and stability in shared systems.

By creating simulated filesystems, setting restrictions, and enforcing limits, we can effectively regulate space usage for users and groups within specific directories, preventing resource conflicts and promoting equitable access.

Comments are closed on this article!